Is there a formula for textbox widths as a multiple of max. characters?
I assume that if my textbox holds 40 characters, I should be able to plug it into a formula that looks like F(40) = (40 * X + Y).
I think it really depends on the font you are using. I'm sorry for not giving you the formula, but you can find FormattedText class helpful. Especially its Width property.
In case of fixed-width fonts it's as easy as measuring any character width with FormattedText, and multiplying it by number of characters. In other cases things get trickier...
For the time being I'm using width(n) = 11n+8. This is based on the defaults for Windows 7 and the width of the M character.
Related
I have a set of pages that look like this:
I have the content in grids with * Heights and Widths so the grid correctly scales when the entire window resizes. I would like the text to resize with the grid. Basically I would like the user to resize from this:
To this:
(preserving white space)
One way to do this would be to wrap the TextBlock in a ViewBox with margins on the right and bottom (for Grid.Row="3") to account for white space. But because I have several pages with different lengths and line counts I would have to set the margin specifically for each page otherwise the text sizes would differ on each page. Is there a better way to do this??
I don't think there is a better way to do this. There are different ways. But, I think it isn't just a matter of opinion that they would not be better.
Ways I can think of.
Render your text offscreen, rendertargetbitmap that so you've got a picture. Change your textblocks on screen to images and stretch them.
Or
Work out the size your text wants to be. Then do some calculation comes up with a different fontsize which is "better". This is a lot easier to write a description of than do.
In my opinion.
A viewbox is easier to implement. Way less error prone than calculations. Will give at least as good results as rendering to a picture.
I just want to add one more solution to the ones suggested by Andy, which is more of a scientific approach and takes a bit of practice to master.
Suppose you have to find a function F, which maps one or more variables to a desired single value. In your case that would be a function F, which takes aspect ratio of the window as input and outputs an appropriate font size.
How can you find such a function?
Well... you don't need to do any math yourself!
First, you need some data to begin with:
1. Resize the window randomly
2. Calculate aspect ration (X)
3. Pick an appropriate font size that looks good enough (Y)
4. Repeat the measurement 7 to 10 times (sorry data scientists)
5. Enter the data in Excel - one column for X and another one for Y
6. Insert a scatter chart
7. Choose the best trendline for your data, but avoid the polynomial one
8. Display the trendline equation and use the expression in your code
Now I should mention the pros and cons of this regression technique.
Pros:
1. It can solve a wide range of tricky problems:
"I use this 3rd party control, but when the text is too long it overlaps the title bar. How to trim it so it doesn't go beyond the top border?. Deadline is coming!"
2. Even if it doesn't solve the problem perfectly, the results are often acceptable
3. It takes minutes to try out unlike spending a day refreshing your math skills
Cons:
1. The biggest problem is that to keep it simple, you often lower the number of
variables by assuming some of them to be constant. In this post I've assumed that
the font family won't change for example, neither the font weight.
2. If any of the assumptions does not hold the final result could be even worse
This technique is fragile, but powerful. Use it as your last weapon and never leave magic expression like
fontSize = (int)(0.76 + 1.2 * aspectRation) without documenting how it came to be.
I have written some code to automatically scale a CheckedListBox to its contents using mListBox.ItemHeight and mListBox.CreateGraphics().MeasureString(...).
The output from the string measurements is a bit dubious but what really puzzles me is how much to add for borders and such.
I tried both SystemInformation.Border3DSize (= 2) as well as the difference between ClientSize and Size (= 4).
But taking mListBox.ItemHeight * mListBox.Items.Count + 4 for the height makes it one pixel too small and a scrollbar appears.
For the width it does not work at all because it does not take the size of the checkboxes into account for which I can't seem to find a source.
How should I determine the size of the control?
In cases like this, it is typically easier to set the ClientSize rather than the whole Size. One thing to note about ItemHeight is that it does not include the margins of the item. Using a CheckedListBox with default settings, I had an ItemHeight of 13. But the ItemRectangle property had a height of 15.
So here is what I did. I added 9 items to the CheckedListBox (the first Item was longer than the rest), keeping the default size of the control as set by the designer. Then in the constructor of the form, I set the ClientSize like so:
this.checkedListBox1.ClientSize = new Size(TextRenderer.MeasureText(checkedListBox1.Items[0].ToString(), checkedListBox1.Font).Width + 20, checkedListBox1.GetItemRectangle(0).Height * checkedListBox1.Items.Count);
Notice I used TextRenderer.MeasureText to measure the text. It will typically give you better values than Graphics.MeasureString. By default, TextRenderer included a bit of padding in it's measurement. I also included a 20 pixel padding to account for the checkbox. Anyway, with TextRenderer.MeasureText, and the 20 pixel padding for width, and ItemRectangle * Items.Count for the height, that gave me a CheckedListBox that was sized to its contents without ScrollBars.
EDIT: If item widths vary, it may complicate setting the width, as you'll want to set the width based on the longest item. In this case you'll need to measure each item and keep track of which one was the longest.
EDIT 2: Ok so I dug around in the CheckedListBox source code. They use a default size of 13 plus a 3 pixel padding for the width and height of the checkbox. But, if VisualStyles is enabled, they call CheckBoxRenderer.GetGlyphSize to get the size to use because it takes into account the DPI settings. Most machines are set at 96 DPI so that method will still return a size of (13,13). So when you're measuring the text of the item, you can also pass the Graphics object and a CheckBoxState enum to the CheckBoxRenderer.GetGlyphSize to get a size. I used System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal for the state, but I'm not sure that the state matters. I tried CheckBoxState.MixedDisabled as well and it returned the same size, (13,13).
So to summarize, you can use CheckBoxRenderer to get the size of the checkbox, but you will still probably need to use some padding. This reduces the need for hardcoding a magic number to account for the checkbox. Since the checkbox is drawn and isn't an actual control, its size can't be determined like sizes of controls can.
Here is a link to the source of CheckedListBox. It wouldn't hurt to look at it. Specifically, look at the protected override void OnDrawItem method.
CheckedListBox Source
I want to stretch the text in a label to fill the width of the label using VB.NET code. This is in a WPF application.
I have tried numerous methods including changing only the font size like this:
scale = 0.25
lbl.FontSize = l.Width * scale
The problem with this method is I need the height to remain the same for all labels and the 0.25 was a guess that gives approximately the correct fill for a string of 4 characters
I tried a recursive method where I change the font size in small increments and compare the string width to the label width until it fits.
Transformations was also considered and it would looks like a good bet:
w = lbl.Width
scale = lbl.content.length/100
lbl.LayoutTransform = New System.Windows.Media.ScaleTransform(w * scale, 1)
This solves my problem of hight but I still need to guess the factor of transformation until it sort of works. Also the stretched text lose it quality and becomes distorted as expected.
Is there any way to reduce the distortion effect on text when its transformed. Perhaps some fonts that display better than other on after transformations?
Hi Guyz I have a WPF TextBlock of fixed width say 100 , If the string doesnt fit in the width the last character is being cutoff always as all the characters are of not the same size. I dont want to cut the character instead I want to skip the text from there and just display the text with no character cutoff.
You have a couple of options to control wrapping and cutting of text:
TextWrapping can be used to make the text flow to the next line
TextTrimming can be used to decide how to cut text that doesn't fit
TextTrimming=None (the default) will mean that text which doesn't fit will be hidden, but it may cut down the middle of a character, which sounds like the problem you describe.
TextTrimming=WordEllipsis or TextTrimming=CharacterEllipsis will avoid showing half a character, but will append "..." to the end of the text. That will probably look better to users.
If you want to cut off the extra characters without adding the ellipsis, you'd have to use the technique Ed S. described
I suppose that I don't really understand your use case here. My first suggestion would be to simply dynamically size your TextBlock. If that's not possible then you wil have to get the width of the string and manipulate it yourself before you set it in the TextBlock (or use a fixed width font assuming that you can and you know the max length of the string).
If you need to measure the width of the string before it is displayed you can use the FormattedText class to do so.
I have a chart in WPF with a lot of labels. The text on these labels is dynamically loaded and subject to change. If I set the width just to auto, then these labels may overlap, which makes the text unreadable.
The chart support multiple sizes, so if it gets larger, then the bars are re sized and there is more space for text. Now I want to adjust the text to the space which is available. If it gets too small, I don't want to display the label anymore (a tooltip is available, so the user still gets the required information). Consider the string "Case 1, blah blah", there is probably not enough space to display the whole string, but just the first word. In this case I want the string to be "Case 1..", with .. indicating that there is some more information in the tooltip.
I can determine the length available for the string. But how can I determine the space a single letter will take? Of course I could also just re size the label, but then it would just cut off the string anywhere which is probably not helpful for the user (and looks ugly).
Any ideas?
If you can use TextBlocks instead of labels then they have a TextTrimming property which will do this for you to either the nearest character or the nearest word.
While you seem happy with the TextTrimming property, I'll edit this to add that the TextBox control has a GetRectFromCharacterIndex method that would allow you to find out the size on screen of one or more characters as long as the font settings matched your label. This might be useful if you wanted to trim at specific places in the label rather than the nearest character / word.
Not an expert in WPF, but I would think that you'll need to do this in code rather than XAML.
Start by obtaining the actual pixel width of the space available for the text.
Then look at the character set, dot pitch etc. utilised on the XAML front end and from there calculate the pixel width required per character.
You could also look at changing the character sizes as well as reducing the label length.