how to check whether a string can fit into richtextbox visible area - c#

I want to divide a very large string into slices so that each slice can fit into the visible area of a richtextbox so that the horizontal scroll bar will not show.
I would like to know how to determine whether a string can fit into the richtextbox's visible area without changing the richtextbox's value.
I searched for the solution and most results I found suggest that MeasureText / MeasureString should be used, but it seems these two function assume there is only one line(not wrapped).
Is there any way to find out the height of a multiple line string which will be set into a richtextbox?

MeasureText and MeasureString functions has overloads that accept textarea width, height and TextFormatFlags(TextBoxControl, WordBreak e.t.c)
You can compare your text size with RichTextBoxControl size
Size stringSize = new Size();
string text = SomeText();
stringSize = TextRenderer.MeasureText(text, richTextBox1.Font, new Size(richTextBox1.Size.Width, richTextBox1.Size.Height), TextFormatFlags.WordBreak);
string r = string.Format("RTB Width : {0}\r\n", richTextBox1.Size.Width);
r += string.Format("RTB Height : {0}\r\n", richTextBox1.Size.Height);
r += string.Format("TEXT Width : {0}\r\n", stringSize.Width);
r += string.Format("TEXT Height : {0}", stringSize.Height);
MessageBox.Show(r);

Related

Calculate character capacity of a textbox with known Width and Height and Font in wpf

I am trying to calculate how many characters or Text can fit in a TextBox with Wrap.
And I want to remove the over flow text.
I am passing the string to a TextBox at runtime and I want to truncate the extra part of the string and display only the Substring which can easily fit into TextBox of dynamic width and Height and font.
User can specify any width and Height and any font.
Is there any way to calculate number of characters which can fit in the text box of given Height and Width in WPF?
I have Tried to achieve this like:
`
if (fontSize <=minimumFontSize &&
formattedText.WidthIncludingTrailingWhitespace > textBoxWidth)
{
do {
//reduce length;
length -= 1;
truncationText = formattedText.Text.Truncate(length);
formattedText= GetFormattedText(myTextBox, truncationText);
}
while (fontSize <=minimumFontSize && formattedText.WidthIncludingTrailingWhitespace > textBoxWidth)
`

How to get the part of string fitted in a rectangle layout by text renderer

I am trying to draw a string on a bitmap, but if the text is too long, part of the text may be clipped by text renderer. If I can find which part of text was written I can write the rest of it on another bitmap.
Is there any text rendering function in C# so it gets a text and a proposed layout rectangle and returns the amount of string written (fitted) in the layout rectangle?
string fittedString = TextRenderer.DrawText(graphics, text, rectangle);
If no, what is the easiest way to accomplish it?
Not one that I know of, but you can get an approximate by calling MeasureText() on each character of your string in a loop and sum up returned widths in a variable say W. When your sum exceeds the width of your target rectangle, you simply pick max value char height of that line in a separate variable say H. Upon reaching the end of each line you add the max value of height of current line in H.
You keep doing this until the value of H exceeds your target rectangle's height. That is simply the number of chars that fit in your rectangle.
Something like this (written by hand, plz adjust):
int HowManyChars(Graphics g, Font font, string text, Rectangle r)
{
float W=0, H=0, MaxH=0;
int i=0;
for(i=0; i< text.Length; i++)
{
var sz = g.MeasureString(text[i].ToString(), font);
W+= sz.Width;
if(W > r.Width)
{
W=sz.Width;
H+=MaxH;
MaxH = 0;
if(H>r.Height) break;
}
else
{
if(sz.Height > MaxH) MaxH = sz.Height;
}
}
return i;
}
TextRenderer.MeasureText(...) method returns a Size value which determines the size needed to draw a text. However, this method requires that the text is drawn on a single line. TextFormatFlags.WordBreak option makes it to wrap the text in a proposed layout.
We set the width of the proposed layout to the target rectangle width and in a loop measure the size of a substring of the main text rendered in this layout. if the size.Height returned by the method exceeds the height of our target rectangle, then we stop and return the index.
int HowManyChars(Font font, string text, Rectangle r)
{
int i = 0;
for (; i < text.Length; i++)
{
string str = text.Substring(0, i);
var size = TextRenderer.MeasureText(str, font,
new Size(r.Width, 0), TextFormatFlags.WordBreak);
if (size.Height > r.Height)
break;
}
return i;
}

Calculate text width based on available height?

Is there any way to calculate text width based on available height in c# on windows forms?
Edit: I have the font size. I want to calculate the minimum width required for drawing the text considering the line could be wrapped.
what you can do is to measure a string in a default size with this method:
(g is a Graphics Object)
g.MeasureString("area", Font, maxWidth)
you scale the fontsize depending on the proportion measuredHeight to availableHeight. After you can remeasure the string with the height of the available area
or you just measure it to get the proportions and calculated the expected width like that:
float measureFontSize = 5;
SizeF measuredBox = g.MeasureString("my string", new Font("Arial", measureFontSize));
double measuredProportion = measuredBox.Width / measuredBox.Height;
double expectedWidth = measuredProportion * wishedHeight;

How to AutoSize the height of a Label but not the width

I have a Panel that I'm creating programmatically; additionally I'm adding several components to it.
One of these components is a Label which will contain user-generated content.
I don't know how tall the label should be, but it does have a fixed width.
How can I set the height so that it displays all the text, without changing the width?
Just use the AutoSize property, set it back to True.
Set the MaximumSize property to, say, (60, 0) so it can't grow horizontally, only vertically.
Use Graphics.MeasureString:
public SizeF MeasureString(
string text,
Font font,
int width
)
The width parameter specifies the
maximum value of the width component
of the returned SizeF structure
(Width). If the width parameter is
less than the actual width of the
string, the returned Width component
is truncated to a value representing
the maximum number of characters that
will fit within the specified width.
To accommodate the entire string, the
returned Height component is adjusted
to a value that allows displaying the
string with character wrap.
In other words, this function can calculate the height of your string based on its width.
If you have a label and you want have control over the the vertical fit, you can do the following:
MyLabel.MaximumSize = new Size(MyLabel.Width, 0)
MyLabel.Height = MyLabel.PreferredHeight
MyLabel.MaximumSize = new Size(0, 0)
This is useful for example if you have a label in a container that can be resized. In that case, you can set the Anchor property so that the label is resized horizontally but not vertically, and in the resize event, you can fit the height using the method above.
To avoid the vertical fitting to be interpreted as a new resize event, you can use a boolean:
bool _inVerticalFit = false;
And in the resize event:
if (_inVerticalFit) return;
_inVerticalFit = true;
MyLabel.MaximumSize = new Size(MyLabel.Width, 0)
MyLabel.Height = MyLabel.PreferredHeight
MyLabel.MaximumSize = new Size(0, 0)
_inVerticalFit = false;

LinkLabel needing more space than TextRenderer.MeasureText says

If I give TextRenderer.MeasureText some text to measure and width to use it will return the height needed to display that text.
private static int CalculateHeight(string text, Font font, int width)
{
Size size = TextRenderer.MeasureText(text, font, new Size(width, Int32.MaxValue), TextFormatFlags.NoClipping | TextFormatFlags.WordBreak);
return size.Height;
}
If I give that text, width and height to a LinkLabel it would display the text in the width and height provided with nothing clipped off.
However, if I put a Link into the LinkLabel.Links collection, the LinkLabel will draw the text with what appears to be a little more spacing between the characters and at times this will cause the end of the text to be clipped. Is there anyway to prevent this? I've tried adding padding when there is a link, but there's no reliable way to know exactly how much more space will be needed. Are there any other ways to do this?
You should use Control.GetPreferredSize method to calculate width or height needed for control (LinkLabel in your case). You should not use MeasureText for such purposes, more detailed explanation you can find here (Accuracy of TextRenderer.MeasureText results.)
If a LinkLabel contains more than one link, or there are parts of text which are nor in a link, then the control uses Graphics.DrawString/MeasureString instead of TextRenderer.DrawText/MeasureText. You can easily see it in action, the biggest difference in rendering is with the small L letter:
linkLabel1.Text = new string('l', 100); // 100 x small L
linkLabel1.LinkArea = new LinkArea(0, 50);
linkLabel2.Text = new string('l', 100); // 100 x small L
TextRenderer.MeasureText is a managed wrapper for the DrawTextEx API. The value returned comes from the lprc struct. You might want to look at that API for more details.
I guess you could remove the style that makes it underline. linkLabel.Styles.Add("text-decoration", "none"); but then of course it wouldn't look like a link. :-/
Another solution would be to add the padding yourself I guess.
int heightBefore = linkLabel.Height;
int fontHeight = CalculateHeight(linkLabel.Text, linkLabel.Font, linkLabel.Width);
int paddingHeight = heightBefore - fontHeight;
linkLabel.Font = otherFont;
linkLabel.Height = CalculateHeight(linkLabel.Text, otherFont, linkLabel.Width);
linkLabel.Height += paddingHeight;
Not the prettiest of solutions, but I would guess it works.

Categories

Resources