Resize form depending on text length - c#

I'm developing a desktop application in C#, which shows pop-up messages every X quantity of time. For this, I'm using a library called PopupNotify, and I'd like the label that contains the message(called NotifyMessage) to have a fixed width, and vertically enlarge on overflow.
There is an event in which they set this up, but I can't modify it to make it work. Here is the event's code:
private void SetLayout()
{
int padding = 8;
int iconRightPadding = 0;
int border = 1;
iconBox.Left = padding + border;
iconBox.Top = padding + border;
iconBox.Width = IconWidth;
iconBox.Height = IconHeight;
this.Height = iconBox.Height + 2 * padding + 2 * border;
closeButton.Left = Width - padding - border - closeButton.Width + 3;
closeButton.Top = padding + border - 3;
NotifyTitle.Top = iconBox.Top - 5; //fudge factor
NotifyTitle.Left = iconBox.Right + iconRightPadding;
NotifyMessage.Left = NotifyTitle.Left + 1; //fudgy
NotifyMessage.Width = Width - NotifyMessage.Left - padding - border;
NotifyMessage.Top = NotifyTitle.Bottom;
NotifyMessage.Height = Height - NotifyMessage.Top - padding - border;
}
I've tried modifying it's logic, and the way it calculates its height by adding the NotifyMessage's height, and some other things, but none of them worked.
I'll appreciate any help on this.

You'll need to use TextRenderer.MeasureText to calculate required height of the label. This should be close:
public static int CalcLabelHeight(Label lbl) {
Size sz = new Size(lbl.ClientSize.Width, Int32.MaxValue);
sz = TextRenderer.MeasureText(lbl.Text, lbl.Font, sz, TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
int height = sz.Height;
if (height < lbl.Font.Height) height = lbl.Font.Height;
return height + lbl.Padding.Vertical;
}
From there, set the form's ClientSize property to fit the label.

From my comment:
try docking that beautiful label

Something like this:
Graphics g = wnd.CreateGraphics();
String s = "Your string";
SizeF size = g.MeasureString(Font, s);
myHeight = size.Height + padding + border;
Use StringFormat as an argument to MeasureString to specify wrapping options when calculating the correct height.

Related

Label is possible part text for left and part text to right?

Label is possible part text for left and part text to right?
int x = 5;
label1.Text = "MY TEXT FROM LEFT : " + x.ToString();
Where, x from right?
This Visual Studio 2013 and Windows Forms Application
My new idea:
string length = "";
for (int i = 0; i < 50; i++)
length += " ";
label1.Text = "MY TEXT FROM LEFT : " + length + x.ToString();
But, length of my window = ???
If I understand you correctly, perhaps something like this is what you're trying to achieve?
var leftString = "Left string:";
var rightString = "Right string";
var graphics = textBox1.CreateGraphics();
var leftStringWidth = (int) graphics.MeasureString(leftString, textBox1.Font).Width;
var rightStringWidth = (int) graphics.MeasureString(rightString, textBox1.Font).Width;
var spaceWidth = (int) graphics.MeasureString(" ", textBox1.Font).Width;
var padding = new string(' ',
(textBox1.Width - leftStringWidth - rightStringWidth) / spaceWidth);
textBox1.Text = leftString + padding + rightString;
Output
You could subscribe to the paint event to draw the underline and second string:
private void label1_Paint(object sender, PaintEventArgs e)
{
var rightString = "Right string";
var rightStringWidth = e.Graphics.MeasureString(rightString, label1.Font).Width;
var rightStringXLocation = label1.Width - rightStringWidth;
using (var brush = new SolidBrush(label1.ForeColor))
{
e.Graphics.DrawString(rightString, label1.Font, brush, new PointF(rightStringXLocation, 0));
var lineHeight = label1.Height - 5;
e.Graphics.DrawLine(new Pen(brush), e.Graphics.MeasureString(label1.Text, label1.Font).Width, lineHeight, rightStringXLocation, lineHeight);
}
}
To resize automatically with the window you will also need to set Anchor to Left, Right:
this.label1.Anchor = (AnchorStyles)(AnchorStyles.Left | AnchorStyles.Right);
Configure your label as follows:
Anchor: Top, Left, Right
Autosize: False
TextAlign: TopRight
And widen your label to window width. This way the text will be aligned to the right of the form.
UPDATE:
Try the following code to measure width and set appropriate number of underlines. Note that we measure 1000 of underlines to make it more precise. Button and Random are added for demonstration puproses. The result is not 100% precise, but you can't achieve more with just adding underline characters.
private Random _rnd = new Random(DateTime.Now.Millisecond);
private static float measureTextWidth(string text, Font font, Graphics g)
{
SizeF size = g.MeasureString(text, font);
return size.Width;
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics g = label1.CreateGraphics())
{
string leftText = "Some caption";
string rightText = new string('V', _rnd.Next(50));
float leftWidth = measureTextWidth(leftText, label1.Font, g);
float rightWidth = measureTextWidth(rightText, label1.Font, g);
float underlineWidth = measureTextWidth(new string('_', 1000), label1.Font, g );
underlineWidth = underlineWidth / 1000.0f;
float allSpacesWidth = this.Width - leftWidth - rightWidth;
int numberOfSpaces = (int)(allSpacesWidth / underlineWidth);
label1.Text = leftText + new string('_', numberOfSpaces) + rightText;
}
There is advanced method to measure string size if Graphics.MeasureString will be not precise enough:
https://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations
If you can use 2 labels instead of one:
Place TableLayoutPanel (with docking or anchor as you need) on your form.
Panel should have 1 row and 2 columns (AutoSize)
Add 2 labels to panel (one with anchor Left second with anchor Right)
set "left text" to first label and "right text" to second one.

How to set the vertical alignment for the WindowsForms TextBox?

In WPF it has the default support for the vertical alignment for the TextBox control. but in Windows Forms there is no way to set the vertical alignment of the TextBox control.
In My case, I have using the multi-line text box and the text is need to be displayed on the bottom of the TextBox and it need to be maintain the alignment while typing on it.
I have tried to get the line count of the entered text and try to calculate the bounds of the text box based on the length of the text. but the line count is not get properly when editing the text with word wrap.
Can any one help me on this to maintain the vertical alignment of the TextBox while editing?
I have tried to change the location of the textbox using the suggestion given in that thread. when editing the text. When I try to edit the text the bounds is not updated properly and some part of the text is hidden in the text box. I have calculated the bounds based on the font size and text width.
Size textSize = TextRenderer.MeasureText(TextBoxText, this.textBoxControl.Font);
int textBoxTop = this.textBoxControl.Bounds.Top;
int nol = (textSize.Width > this.textBoxControl.Width) ? ((textSize.Width) / this.textBoxControl.Width) + 1 : 1;
{
if (nol > n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (top + (height - nol * textSize.Height) > top)
{
rect1.Y = top + (height - nol * textSize.Height);
rect1.Height = nol * textSize.Height;
this.textBoxControl.Bounds = rect1;
}
else
{
this.textBoxControl.Bounds = rect1;
}
}
else if (nol < n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (rect1.Y + nol * textSize.Height < top + height)
{
rect1.Y += textSize.Height - this.textBoxControl.Margin.Top;
rect1.Height -= textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
if (nol == 1)
{
rect1.Y = top + height - textSize.Height;
rect1.Height = textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
this.textBoxControl.Bounds = rect1;
}
}
Its working fine while editing the text, but in some cases the nol Line count is calculated wrongly. How can I get the actual line count of the textbox including the wrapped lines.?
I have created a control that has a TextBox docked to the bottom of a panel that looks kinda like a TextBox:
// Make sure you have this.
using System.Linq;
public class BottomAlignTextBox : Panel
{
public BottomAlignTextBox()
{
this.BackColor = Color.White;
this.BorderStyle = (Application.RenderWithVisualStyles) ? BorderStyle.FixedSingle : BorderStyle.Fixed3D;
this.Size = new Size(200, 200);
this.Padding = new Padding(5, 0, 4, 2);
bottomAlignTextBox.Dock = DockStyle.Bottom;
bottomAlignTextBox.Multiline = true;
bottomAlignTextBox.WordWrap = true;
bottomAlignTextBox.AcceptsReturn = true;
bottomAlignTextBox.BorderStyle = BorderStyle.None;
bottomAlignTextBox.Height = 20;
bottomAlignTextBox.TextChanged += delegate
{
if (bottomAlignTextBox.Height < this.Height - 20)
{
if (TextRenderer.MeasureText(bottomAlignTextBox.Text, bottomAlignTextBox.Font).Width > bottomAlignTextBox.Width + 6)
{
string longestLine = bottomAlignTextBox.Lines.OrderByDescending(s => TextRenderer.MeasureText(s, bottomAlignTextBox.Font).Width).First();
bottomAlignTextBox.Text = bottomAlignTextBox.Text.Replace(longestLine, longestLine.Substring(0, longestLine.Length - 1) + Environment.NewLine + longestLine[longestLine.Length - 1]);
bottomAlignTextBox.Height += 19;
bottomAlignTextBox.SelectionStart = bottomAlignTextBox.Text.Length + 2;
bottomAlignTextBox.SelectionLength = 0;
}
}
};
this.Controls.Add(bottomAlignTextBox);
this.Click += delegate { bottomAlignTextBox.Focus(); };
}
public new string Text
{
get { return bottomAlignTextBox.Text; }
set { bottomAlignTextBox.Text = value; }
}
private TextBox bottomAlignTextBox = new TextBox();
}
I am not sure if that is entirely possible, but I think you can wrap the control with a Panel control or some sort and Dock it to the bottom of the wrapping Panel control? If the size needs to be dynamic, playing around the Anchor properties should work as well.

Why does my form need to be bigger than its containing panels to display them?

I'm using simple code to generate a grid (gridSize * gridSize fields with lines dividing them in column and row, basically a TicTacToe grid).
As I'm creating the panels dynamically during Form_Load, I need to also adjust the size of the form. However, setting it to gridSize * tileSize, gridSize * tileSize is not big enough - I found by experimentation that I need to add ~15 to width and ~40 to height for gridSize = 3 and tileSize = 120. Why is this?
Code below:
private void Form1_Load(object sender, EventArgs e)
{
const int tileSize = 120;
const int gridSize = 3;
/* Here: When setting size, I need to add 15 and 40? */
this.Size = new System.Drawing.Size(tileSize * gridSize + 15, tileSize * gridSize + 40);
// initialize the "board"
tictactoeFields = new Panel[gridSize, gridSize]; // column, row
// double for loop to handle all rows and columns
for (var n = 0; n < gridSize; n++)
{
for (var m = 0; m < gridSize; m++)
{
// create new Panel control which will be one
// tic tac toe field
var newPanel = new Panel
{
Size = new Size(tileSize, tileSize),
Location = new Point(tileSize * n, tileSize * m)
};
// add to our 2d array of panels for future use
tictactoeFields[n, m] = newPanel;
newPanel.BackColor = Color.White;
if(n != 0)
{
// Draw a line in front (to the left) of this panel
Panel leftSeparator = new Panel
{
Size = new Size(1, tileSize),
Location = newPanel.Location,
BackColor = Color.Black
};
Controls.Add(leftSeparator);
}
if(m != 0)
{
// Draw a line on top (above) this panel
Panel topSeparator = new Panel
{
Size = new Size(tileSize, 1),
Location = newPanel.Location,
BackColor = Color.Black
};
Controls.Add(topSeparator);
}
}
}
foreach(Panel pan in tictactoeFields)
{
// add to Form's Controls so that they show up
Controls.Add(pan);
}
}
The Size property is just a shorthand for setting the size of the Bounds property which includes nonclient elements such as scroll bars, borders, title bars, and menus.
What you should do is to set the size of the ClientRectangle property, or use the ClientSize shorthand.
There's also a DisplayRectangle property which includes padding, but in this case use the ClientRectangle property.
this.ClientSize = new Size((tileSize * gridSize), (tileSize * gridSize));

Label text appearing too low

I want to display two numbers in a full-screen manner,
above each other,
as regardless of actual screen size as possible.
//getting screen size and setting window to maximized
Rectangle screenEdge = Screen.PrimaryScreen.Bounds;
this.Width = screenEdge.Width;
this.Height = screenEdge.Height;
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
this.WindowState = FormWindowState.Maximized;
//using 90% of width and 40% (times two) of height
int lWidth = (int)(this.Width * 0.9);
int lHeight = (int)(this.Height * 0.4);
//horiz. spacing: remainder, divided up for left and right
int lLeft = ( this.Width - lWidth ) / 2;
//vert. spacing: remainder divided for top, bottom and between
int lTop = ( this.Height - (2 * lHeight)) / 3 ;
//the labels holding the numbers
lSoll = new Label();
lIst = new Label();
//setting label lSoll to calc'd dimensions, adding & aligning text
lSoll.Left = lLeft;
lSoll.Width = lWidth;
lSoll.Top = lTop;
lSoll.Height = lHeight;
Font sollFont = new Font(FontFamily.GenericSansSerif, lSoll.Height);
Font sFSized = new Font(sollFont.FontFamily, lSoll.Height);
lSoll.Font = sFSized;
lSoll.TextAlign = ContentAlignment.MiddleCenter;
lSoll.ForeColor = Color.Blue;
lSoll.BackColor = Color.White;
updateSollText(42);
//same as above, just a bit lower
lIst.Left = lLeft;
lIst.Width = lWidth;
lIst.Top = lTop * 2 + lSoll.Height;
lIst.Height = lHeight;
Font istFont = new Font(FontFamily.GenericSansSerif, lIst.Height);
Font iFSized = new Font(istFont.FontFamily, lIst.Height);
lIst.Font = iFSized;
lIst.TextAlign = ContentAlignment.TopCenter;
lIst.ForeColor = Color.Red;
lIst.BackColor = Color.White;
updateIstText(39);
Issue with this code (besides clumsyness):
The text on the labels is displayed partly below the labels' lower bounds, i.e. invisible,
see screenshot at the bottom.
I double checked my calculations and found that other than a rounding error of 1 pt (tops) it all should work.
I also tried making the fontsize less than label height, which helped a little but was certainly not a fix.
I actually though the textalign should cover this, because that is what it is for.
Also chaning the height-comp(low middle top) of textalign did not change anything, whereas left / center / right do make the difference expected
What could be causing this?
The default unit of measurement for a font is points, not pixels. For example, with a default DPI setting of 96, a 9 point font takes up 9 * 96 / 72 = 12 pixels. So the font you ask for is too big and doesn't fit.
The workaround is simple, you can specify the unit of measurement you prefer with a Font constructor overload that takes a GraphicsUnit argument. Fix:
Font sollFont = new Font(FontFamily.GenericSansSerif, lSoll.Height, GraphicsUnit.Pixel);
Font sFSized = new Font(sollFont.FontFamily, lSoll.Height, GraphicsUnit.Pixel);

Resizing label width depending on the width of its content

I'm working on a code-editor and want to auto-adjust the width of a label as the number increases. For example, for 1-9 (1 digit) there's a specific width. Then when it gets to 10-99 (2 digits), width of label increases. Then again for then 100-999 (3 digits), etc.
The result should be something like this:
Here is my code:
private void timer_countline_Tick(object sender, EventArgs e)
{
updateNumberLabel();
}
private void updateNumberLabel()
{
// we get index of first visible char and number of first visible line
Point pos = new Point(0, 0);
int firstIndex = rtb.GetCharIndexFromPosition(pos);
int firstLine = rtb.GetLineFromCharIndex(firstIndex);
// now we get index of last visible char and number of last visible line
pos.X = ClientRectangle.Width;
pos.Y = ClientRectangle.Height;
int lastIndex = rtb.GetCharIndexFromPosition(pos);
int lastLine = rtb.GetLineFromCharIndex(lastIndex);
// this is point position of last visible char, we'll use its Y value for calculating numberLabel size
pos = rtb.GetPositionFromCharIndex(lastIndex);
// finally, renumber label
numberLabel.Text = "";
for (int i = firstLine; i <= lastLine + 1; i++)
numberLabel.Text += i + 1 + "\n";
}
You can use TextRenderer for doing what you want. Please check the following code lines (You should add the code lines to TextChanged event of your label):
Please remember that the AutoSize property of your controls must set to False.
This is for changing Width of your control to fit with width of its contents.
yourLabelName.Width = TextRenderer.MeasureText(yourLabelName.Text, yourLabelName.Font).Width;
This is for changing Height of your control to fit with height of its contents.
yourLabelName.Height = TextRenderer.MeasureText(yourLabelName.Text, yourLabelName.Font).Height;
Update 1:
For changing your panel Width for showing all contents in it horizontally, you can use the followng code line:
yourPanelName.Width = yourLabelName.Left + yourLabelName.Width;
For changing your panel Height for showing all contents in it vartically, you can use the followng code line:
yourPanelName.Height = yourLabelName.Top + yourLabelName.Height;
Update 2:
If you are used SplitContainer control, you must change the properties of your SplitContainer as follows:
FixedPanel = none
IsSplitterFixed = False
Then you can use the following lines of code for achieve to what you want:
For changing your SplitContainer panel Width for showing all contents in it horizontally, you can use the followng code line:
int yourLabelNameWidth = TextRenderer.MeasureText(yourLabelName.Text, yourLabelName.Font).Width;
yourSplitContainerName.SplitterDistance = yourLabelName.Left + yourLabelNameWidth;
yourLabelName.Width = yourLabelName.Left + yourLabelNameWidth;

Categories

Resources