I need a label to appear in the middle bottom (like 30px above the bottom line) of a panel, that also auto sizes to wrap the text depending on how long the text is.
So far I can only have the label auto size to wrap the text and have it docked at the bottom. But it is at bottom left and not middle.
As is on this example Long Text Image and Image of short text I'd like to center
(sorry the text is not clear but its at the bottom in white)
I was able to achieve the auto size using the ClientSizeChanged event as below.
private void Panel1_ClientSizeChanged(object sender, EventArgs e)
{
label8.MaximumSize = new Size((sender as Control).ClientSize.Width - label8.Left, 10000);
}
How do I have the text at the middle? It should be able to maintain the bottom middle (dock) position as I resize the panel.
Try following:
To your panel add TableLayoutPanel with following Properties:
tableLayoutPanel1.AutoSize = true; // This can be set at the end if you use designer
tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.RowCount = 1;
tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
panel1.Controls.Add(tableLayoutPanel1); // add TableLayoutPanel to your panel
tableLayoutPanel1.Controls.Add(label1, 0, 0); // Add your label to TableLayout
And set properties on Label:
label1.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
label1.AutoSize = true;
label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Now you can set
tableLayoutPanel1.AutoSize = true;
It is kind of tricky but should give you what you need.
How do I get the character before the position in RichEditControl
for example, A is before the caret, the return string should be A
and in text change I need to get the caret position
You can use the RichEditControl1.Document.CaretPosition property to get the current position then just use string.Substring(0, position.ToInt()) to get the string before the current position of the caret.
check the code snippet below:
private void simpleButton1_Click(object sender, EventArgs e)
{
DevExpress.XtraRichEdit.API.Native.DocumentPosition position = richEditControl1.Document.CaretPosition;
if (richEditControl1.Document.Text.Length > 0)
{
//Returns all previous text befor the caret
XtraMessageBox.Show(richEditControl1.Document.Text.Substring(0, position.ToInt()));
int intPosition = position.ToInt();
if (intPosition > 0 && intPosition < richEditControl1.Document.Length)
{
//It will return previous character
XtraMessageBox.Show(richEditControl1.Document.Text.Substring(intPosition - 1, 1));
}
}
}
References:
How to get RepositoryItemRichEdit caret position
How to get/set the caret position within the editor?
Hope this help.
According to my understanding, the code below should right-justify the text if the text is longer than the textbox can show, otherwise it keeps it left-justified.
The problem is that it doesn't actually do this and it's acting really odd. Short strings end up right-justified sometimes and long strings are always left-justified.
What am I doing wrong?
private void textBoxCurrentConfig_TextChanged(object sender, EventArgs e)
{
SizeF stringSize = new SizeF();
stringSize = TextRenderer.MeasureText(textBoxCurrentConfig.Text, textBoxCurrentConfig.Font);
float currentTextWidth = stringSize.Width;
float allowedTextWidth = textBoxCurrentConfig.Size.Width - 10;
if (currentTextWidth >= allowedTextWidth) // if the text we want to display is larger than the textbox can hold, right justify it to show the filename
{
textBoxCurrentConfig.TextAlign = HorizontalAlignment.Right; // right justify
}
else // otherwise we can display the entire path
{
textBoxCurrentConfig.TextAlign = HorizontalAlignment.Left; // left justify
}
textBoxCurrentConfig.Refresh();
this.Refresh();
}
As from your comments, you want to move cursor position according to the text length. You can use TextBox.Select() method for this. Check MSDN for details.
So if you want to move cursor at the the start of text, you can use
textBoxCurrentConfig.Select(0, 0);
and if you want to move cursor at the end of text, you can use
textBoxCurrentConfig.Select(textBoxCurrentConfig.Text.Length, 0);
Try to remove
this.Refresh();
It's may cause the page to refresh and return the text box to the original align
I created (using c#) a grid with border & the parent layout is another grid. When I try to rezise dynamically, it doesn't give the expected behaviour.
I keep the start position (left-top) of border (with grid) fixed & only the right-bottom point is dragged to resize. In the Mouse move event, the width & height are changed depending on the current position.
1) But it always change the start point (left-top) when changing the width & height ?
2) When border get resized the child (grid) doesn't change its dimensions accordingly ? I cann't find any stretching method. But if border is moved, then the child grid moves with it.
Point offsetParent;
.....
private void MouseMoveEvent(object sender, MouseEventArgs e)
{
if (bIsMouseDown)
{
ResizeControl(e);
offsetParent = e.GetPosition(parentGrid); //reset offset to current
}
}
private void ResizeControl(MouseEventArgs e)
{
// get current point
Point CurPosParent = e.GetPosition(parentGrid);
// current & new position difference
Point diff = new Point(CurPosParent.X - offsetParent.X, CurPosParent.Y - offsetParent.Y);
// keep start point (left-top position) of border fixed
// adjust only width & height of border
border1.Width += diff.X; //changes start point (left-top position) ????
border1.Height += diff.Y;
}
Found out my mistake from this link Object Positioning and Layout
Now I use a Canvas as the parent. Width & height of border & grid can be changed without changing the start point.
Point offsetParent;
.....
private void MouseMoveEvent(object sender, MouseEventArgs e)
{
if (bIsMouseDown)
{
ResizeControl(e);
offsetParent = e.GetPosition(parentCanvas); //reset offset to current
}
}
private void ResizeControl(MouseEventArgs e)
{
// get current point
Point CurPosParent = e.GetPosition(parentCanvas);
// current & new position difference
Point diff = new Point(CurPosParent.X - offsetParent.X, CurPosParent.Y - offsetParent.Y);
// keep start point (left-top position) of border fixed
// adjust only width & height of border
border1.Width += diff.X;
border1.Height += diff.Y;
grid1.Width += diff.X;
grid1.Height += diff.Y;
}
I need a TextBox or some type of Multi-Line Label control which will automatically adjust the font-size to make it as large as possible and yet have the entire message fit inside the bounds of the text area.
I wanted to see if anyone had implemented a user control like this before developing my own.
Example application: have a TextBox which will be half of the area on a windows form. When a message comes in which is will be approximately 100-500 characters it will put all the text in the control and set the font as large as possible. An implementation which uses Mono Supported .NET libraries would be a plus.
If know one has implemented a control already... If someone knows how to test if a given text completely fits inside the text area that would be useful for if I roll my own control.
Edit: I ended up writing an extension to RichTextBox. I will post my code shortly once i've verified that all the kinks are worked out.
I had to solve the same basic problem. The iterative solutions above were very slow. So, I modified it with the following. Same idea. Just uses calculated ratios instead of iterative. Probably, not quite as precise. But, much faster.
For my one-off need, I just threw an event handler on the label holding my text.
private void PromptLabel_TextChanged(object sender, System.EventArgs e)
{
if (PromptLabel.Text.Length == 0)
{
return;
}
float height = PromptLabel.Height * 0.99f;
float width = PromptLabel.Width * 0.99f;
PromptLabel.SuspendLayout();
Font tryFont = PromptLabel.Font;
Size tempSize = TextRenderer.MeasureText(PromptLabel.Text, tryFont);
float heightRatio = height / tempSize.Height;
float widthRatio = width / tempSize.Width;
tryFont = new Font(tryFont.FontFamily, tryFont.Size * Math.Min(widthRatio, heightRatio), tryFont.Style);
PromptLabel.Font = tryFont;
PromptLabel.ResumeLayout();
}
I haven't seen an existing control to do this, but you can do it the hard way by using a RichTextBox and the TextRenderer's MeasureText method and repeatedly resizing the font. It's inefficient, but it works.
This function is an event handler for the 'TextChanged' event on a RichTextBox.
An issue I've noticed:
When typing, the text box will scroll to the current caret even if scrollbars are disabled. This can result in the top line or left side getting chopped off until you move back up or left with the arrow keys. The size calculation is correct assuming you can get the top line to display at the top of the text box. I included some scrolling code that helps sometimes (but not always).
This code assumes word wrap is disabled. It may need modification if word wrap is enabled.
The code:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint wMsg, int wParam, uint lParam);
private static uint EM_LINEINDEX = 0xbb;
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
// If there's no text, return
if (richTextBox1.TextLength == 0) return;
// Get height and width, we'll be using these repeatedly
int height = richTextBox1.Height;
int width = richTextBox1.Width;
// Suspend layout while we mess with stuff
richTextBox1.SuspendLayout();
Font tryFont = richTextBox1.Font;
Size tempSize = TextRenderer.MeasureText( richTextBox1.Text, richTextBox1.Font);
// Make sure it isn't too small first
while (tempSize.Height < height || tempSize.Width < width)
{
tryFont = new Font(tryFont.FontFamily, tryFont.Size + 0.1f, tryFont.Style);
tempSize = TextRenderer.MeasureText(richTextBox1.Text, tryFont);
}
// Now make sure it isn't too big
while (tempSize.Height > height || tempSize.Width > width)
{
tryFont = new Font(tryFont.FontFamily, tryFont.Size - 0.1f, tryFont.Style);
tempSize = TextRenderer.MeasureText(richTextBox1.Text, tryFont);
}
// Swap the font
richTextBox1.Font = tryFont;
// Resume layout
richTextBox1.ResumeLayout();
// Scroll to top (hopefully)
richTextBox1.ScrollToCaret();
SendMessage(richTextBox1.Handle, EM_LINEINDEX, -1, 0);
}
The solution i came up with was to write a control which extends the standard RichTextBox control.
Use the extended control in the same way you would a regular RichTextBox control with the following enhancements:
Call the ScaleFontToFit() method after resizing or text changes.
The Horizontal Alignment field can be used to center align the text.
The Font attributes set in the designer will be used for the entire region. It is not possible to mix fonts as they will changed once the ScaleFontToFit method is called.
This control combines several techniques to determine if the text still fits within it's bounds. If the text area is multiline, it detects if scrollbars are visible. I found a clever way to detect whether or not the scrollbars are visible without requiring any winapi calls using a clever technique I found on one of Patrick Smacchia's posts.. When multiline isn't true, vertical scrollbars never appear so you need to use a different technique which relies on rendering the text using a the Graphics object. The Graphic rendering technique isn't suitable for Multiline boxes because you would have to account for word wrapping.
Here are a few snippets which shows how it works (link to source code is provided below). This code could easily be used to extend other controls.
/// <summary>
/// Sets the font size so the text is as large as possible while still fitting in the text
/// area with out any scrollbars.
/// </summary>
public void ScaleFontToFit()
{
int fontSize = 10;
const int incrementDelta = 5; // amount to increase font by each loop iter.
const int decrementDelta = 1; // amount to decrease to fine tune.
this.SuspendLayout();
// First we set the font size to the minimum. We assume at the minimum size no scrollbars will be visible.
SetFontSize(MinimumFontSize);
// Next, we increment font size until it doesn't fit (or max font size is reached).
for (fontSize = MinFontSize; fontSize < MaxFontSize; fontSize += incrementDelta)
{
SetFontSize(fontSize);
if (!DoesTextFit())
{
//Console.WriteLine("Text Doesn't fit at fontsize = " + fontSize);
break;
}
}
// Finally, we keep decreasing the font size until it fits again.
for (; fontSize > MinFontSize && !DoesTextFit(); fontSize -= decrementDelta)
{
SetFontSize(fontSize);
}
this.ResumeLayout();
}
#region Private Methods
private bool VScrollVisible
{
get
{
Rectangle clientRectangle = this.ClientRectangle;
Size size = this.Size;
return (size.Width - clientRectangle.Width) >= SystemInformation.VerticalScrollBarWidth;
}
}
/**
* returns true when the Text no longer fits in the bounds of this control without scrollbars.
*/
private bool DoesTextFit()
{
if (VScrollVisible)
{
//Console.WriteLine("#1 Vscroll is visible");
return false;
}
// Special logic to handle the single line case... When multiline is false, we cannot rely on scrollbars so alternate methods.
if (this.Multiline == false)
{
Graphics graphics = this.CreateGraphics();
Size stringSize = graphics.MeasureString(this.Text, this.SelectionFont).ToSize();
//Console.WriteLine("String Width/Height: " + stringSize.Width + " " + stringSize.Height + "form... " + this.Width + " " + this.Height);
if (stringSize.Width > this.Width)
{
//Console.WriteLine("#2 Text Width is too big");
return false;
}
if (stringSize.Height > this.Height)
{
//Console.WriteLine("#3 Text Height is too big");
return false;
}
if (this.Lines.Length > 1)
{
//Console.WriteLine("#4 " + this.Lines[0] + " (2): " + this.Lines[1]); // I believe this condition could be removed.
return false;
}
}
return true;
}
private void SetFontSize(int pFontSize)
{
SetFontSize((float)pFontSize);
}
private void SetFontSize(float pFontSize)
{
this.SelectAll();
this.SelectionFont = new Font(this.SelectionFont.FontFamily, pFontSize, this.SelectionFont.Style);
this.SelectionAlignment = HorizontalAlignment;
this.Select(0, 0);
}
#endregion
ScaleFontToFit could be optimized to improve performance but I kept it simple so it'd be easy to understand.
Download the latest source code here. I am still actively working on the project which I developed this control for so it's likely i'll be adding a few other features and enhancements in the near future. So, check the site for the latest code.
My goal is to make this control work on Mac using the Mono framework.
I had a similar requirement for a text box in a panel on a windows form hosted window. (I injected the panel onto the existing form). When the size of the panel changes (in my case) the text would resize to fit the box. Code
parentObject.SizeChanged += (sender, args) =>
{
if (textBox1.Text.Length > 0)
{
int maxSize = 100;
// Make a Graphics object to measure the text.
using (Graphics gr = textBox1.CreateGraphics())
{
for (int i = 1; i <= maxSize; i++)
{
using (var test_font = new Font(textBox1.Font.FontFamily, i))
{
// See how much space the text would
// need, specifying a maximum width.
SizeF text_size =
TextRenderer.MeasureText(
textBox1.Text,
test_font,
new Size(textBox1.Width, int.MaxValue),
TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
try
{
if (text_size.Height > textBox1.Height)
{
maxSize = i - 1;
break;
}
}
catch (System.ComponentModel.Win32Exception)
{
// this sometimes throws a "failure to create window handle" error.
// This might happen if the TextBox is invisible and/or
// too small to display a toolbar.
// do whatever here, add/delete, whatever, maybe set to default font size?
maxSize = (int) textBox1.Font.Size;
}
}
}
}
// Use that font size.
textBox1.Font = new Font(textBox1.Font.FontFamily, maxSize);
}
};