Welcome to Foxite.COM Community Weblog Sign in | Join | Help

Finding the length of a string in a specific font

One of the things that I often found myself doing when working in VFP was trying to decide how large a textbox had to be in order to accommodate the maximum length of the data that was permitted for its underlying source given a specific font and size. As we all know, unless you stick to non-proportional fonts, the number of pixels required to display a string can vary dramatically depending on the font.

For example, the string "Andy Kramek" actually requires 88 pixels when displayed in Courier New, 10 point font. However, change the font to Arial and you need only 79, unless you make it Bold in which case you need 85. But if you change the font to Verdana then you need 85 for the plain text and 96 for Bold.

Given the multiplicity of fonts available you could be forgiven for thinking that determining exactly how much room to allow would be a fairly normal thing to want to do and therefore could reasonably expect VFP would have native function that would tell you. Unfortunately, it doesn't. Now, at this point you may be thinking that this isn't really very important. After all, VFP sizes text boxes automatically using the underlying field definition when you drag a table field from the data environment, or project manager, on to a form.

Unfortunately the native sizing algorithm is not very accurate! For example, dragging a column defined as VARCHAR(50) to a form creates a textbox 357 pixels wide when the font is defined as Arial 9pt. However, the actual size required for a character string of 50 characters (using the average character width for this font) is only about 250 pixels! Even worse, the sizing has nothing to do with the font defined for the form and, even when you change the form's font in the underlying class, VFP simply carries on sizing controls for its default (Arial 9) font. Now that is a lot of wasted space on a form and, even worse, can be confusing to users because the size of the textbox is not a very reliable guide to the amount of text that it can hold.

We also have to consider the situation in which we need to concatenate data which is stored in individual fields together (to display a ‘full’ name for example, or a ‘City, State and Zip’ line for an address). VFP cannot help us here, and so the normal solution is to decide, empirically, how big to make the textbox. There are actually two issues involved here. The first is to determine the number of characters which we want the textbox to be able to handle and the second is to work out the amount of space that number of characters will need given a specific font setting.

Concatenating Fields

The default behavior of VFP when concatenating fields is to simply add together the defined lengths and create a new field whose width matches the total. Consider a set of name fields – let’s assume ‘FirstName’ is set up as 25 characters and ‘LastName’ as 40. Now VFP will always assume the worst case scenario when concatenating these fields and will generate a result field with a width of 65 characters (just run a SQL select that combines two character columns and you will see that this is indeed the case).

However, this does not represent the reality of the situation. Using the sample data that ships with VFP, we find that the average length of first names is actually 5.85 characters, and for last names it is only 6.83. So really we  could use a textbox capable of showing, say, 25 characters and be confident that we would handle the vast majority of cases. While it is impossible to be prescriptive about this sort of concatenation it is easy enough to set a target size that reflects the typical results.

So the number of characters is defined either by the underlying data source directly, or by some reasonable guess based on the required display.

But what about the font?

While we may be able to determine how many characters we want to display easily enough, as we have already seen, the size of the textbox that we need will depend upon the chosen font. In fact it is not only a question of the size of the font, but also of the style (e.g. Bold or Italic) and the font face. Even different fixed pitch fonts vary in their space requirement for individual characters.

Fortunately VFP does have functions, or more accurately a single, heavily overloaded, function to get this information. FONTMETRIC() can access twenty – yes, that’s right, 20 – different font attributes depending on the input parameter. I find it hard to remember the calling options for even one or two of these and even though IntelliSense makes it a little easier we still need to retrieve individual attributes one at a time. Since each returns the value for a single character, the whole process gets tedious, not to say messy, when you are trying to retrieve several attributes for the same string.

The SizeStr() Function

The solution is to create a simple wrapper function to determine the elements of the sizing that we are interested in. While we could grab all 20 attributes, in practice there are really only  three things we are interested in. The maximum length that the specified string could possibly require, the average and the exact lengths of the specified string. With this information we can make a sensible decision based on how typical our test string is, and how much variance we need to allow for in sizing our textbox. The SizeStr() function displays the results in a little modeless form (Figure 1) and returns the exact length of the specified string in the specified font.

 

Figure 1: The SizeStr() Result Screen (the function actually returns the Exact Width)

The exact length of a string is actually calculated as a two step process. First we use the Visual FoxPro TxtWidth() function to determine the number of “Average Character Equivalents” in the test string when the specified font is taken into account. This calculated value allows us to treat proportional fonts as if they were actually fixed and so simplify the ensuing calculation. Thus, while a string containing 5 letters will always return 5 with a fixed pitch font, a proportional font will give different results depending on both the font itself, and any additional styles that have been defined. Table 1 shows the results from TxtWidth() for the string “This is a Test String”.

Having determined how many average character equivalents we have in our text string we can simply multiply this number by the Average Character size (FontMetric(6)) to get the exact size which is returned by the function. To get the Maximum size for a string containing the specified number of characters we then multiply by the Maximum Character Size (FontMetric(7)). Finally we multiply the Average Character size by the actual number of characters in the test string to determine the average length of the string.

But what about the height?

Unfortunately (again) VFP does not help us to decide how high a textbox should be when we change its font. FontMetric() will give us the actual height of the character in a given font, but we also need to allow for border height when sizing a textbox. In SizeStr() I do this by adding a factor of 28.125% of the character height in the specified font. This value has no theoretical basis, but, by inspection appears to be about right! The resulting value is shown on the display form.

The function is attached to this article and can be downloaded below. It accepts the following parameters:

  • tuInStr        [Required]  The input string to be tested
  • tcFName     [Optional (defaults to "Arial")]  The name of the Font    
  • tnFSize       [Optional (defaults to 9 point)]  The font size (in points)       
  • tcFStyle      [Optional] Font Style codes (Bold, Italic, Underline etc)        

The function pops up the modeless window shown at Figure 1, and when the window is closed returns the exact length of the input string in pixels. However, the parameters displayed in the form are all saved to an object in the function and it is simple to suppress the form and return the object directly.

Example

lnLen = SizeStr( “This is a test string”, “Garamond”, 12, “BI” )
? lnLen       && Returns 131

Hopefully you will find this little function as useful as I do.

Published Monday, May 18, 2009 11:49 PM by andykr
Filed Under:
Attachment(s): sizestr.zip

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Finding the length of a string in a specific font

Wednesday, May 20, 2009 8:10 PM by Dantv

Cool stuff - Thanks!

You're very welcome -- AndySmile <img src=" />

# re: Finding the length of a string in a specific font

Thursday, May 21, 2009 8:50 AM by boudewijn lutgerink

Nice, only yesterday I ran into a similar issue and came up with pretty much the same solution. You saved me from writing about it (busy enough preparing the Prague Sessions).
Two minds one idea.

Amazing how often that happens! Give our best to all in Prague, we'll miss not being there -- Andy

# re: Finding the length of a string in a specific font

Wednesday, May 27, 2009 8:25 PM by Ahmed Siddiqui

I check this blog every once ina while. And every time I come here I find gems!! Thanks, Andy. Please don't stop (posting, that is <s>).

Thank you for the encouragement, I appreciate it. Don't worry, as long as I have something to say I'll continue posting (and as those who know me well will tell you, I usually have something to say Wink [;)]) -- Andy

What do you think?

(required) 
required 
(required)