Fonts
Fonts provide control over the visual aspect of text. They define the style of the characters, the size, and any attributes such as bold or italic.
9.2.1 Typographical Stuff
There is a considerable difference between the way a computer user thinks of fonts and the way a traditional typographer thinks of fonts, even if that typographer uses a computer for her font design work. This section looks at fonts from the typical computer user's point of view.
|
Before delving into the properties, methods, and events provided by the Font class, let's review the most common typographic conventions, especially as they apply to .NET applications.
Fonts are classified according to common stylistic features. The broadest classification, is that of serif fonts versus sans serif. A serif is the little frill found at the bottom of the character strokes. Commonly used serif font families include Times New Roman, Garamond, and Palatino. Serif fonts are often referred to as roman fonts (notice the lower case). A sans serif font (Latin for "without serif") does not have these embellishments. The commonly used sans serif fonts include Arial, Tahoma, Verdana, and Helvetica.
Most Windows systems also include one or more fonts, such as Symbols and Dingbats, that don't fall into either category, since they contain mostly non-alphabetic characters (●
Serifs can improve the readability of blocks of printed text. Most newspapers, including The Times of London (which commissioned the original version of the Times font) and the New York Times, as well as most books and magazines use a serif font for body text. Sans-serif fonts are used for body text as well, but especially for headings, captions, and titles. Since they are more compact than the equivalently sized serif font, and also because they tend to look better at low and moderate resolutions than serif fonts, they find common use on computer screens. The default Windows font is called Microsoft Sans Serif.
The next broadest font classification is families. The members of a font family share many design features and are easily recognized as being related. Most (but not all) font families have a base, or regular style. If the character strokes are made heavier, then the font becomes bold. If the characters are slanted to the right and given an extra bit of filigree, then the font becomes italic, or italicized. If slanted only, and not stylized, it is oblique. So, for example, Times New Roman Italic is clearly the italicized version of Times New Roman and Arial Bold is the bold version of Arial.
Strictly speaking, the bold member of a font family has a distinctly different font from the regular member, likewise for the italic and bold italic versions. However, as a practical matter, font users on computers think of the font family as the font, with bold and italic applied as attributes, although there may be additional font families that differ primarily by attribute, such as Arial, Arial Black, and Arial Narrow. The common font dialog supports this viewpoint, as do the constructors of the Font class, as you will see shortly. Windows and the .NET framework also support adding underline and strikethrough effects.
The appearance of a font is often called the typeface, or simply face. Technically, it refers to a specific font, such as Times New Roman Bold. But in the common usage of today, it refers more to the font family, e.g., Times New Roman, which then has style attributes applied.
Each unique font, as distinct from font family, is provided in a separate file on the computer. For example, a standard Windows installation includes Arial.ttf, Arial Bold.ttf, Arial Italic.ttf, and Arial Bold Italic.ttf. The common font dialog sorts the related font files into families and presents the family, Arial in this example, along with the possible styles: regular, bold, italic, and bold italic.
Font sizes are measured in units of points. A point is about 1/72 of an inch. The equivocation is necessary because font metrics in the real world are a non-standard art. Different fonts measure themselves differently. Generally, the point size is measured from the bottom of the descenders, i.e., that part of the characters such as g or y that extend below the baseline, to the top of the ascenders, i.e., that part of the character that extends above the baseline, including the space allowed for diacritical marks. (Diacritical marks added above a character to indicate a special phonetic value, such as the acute [for example, é] and grave [for example, è] accents and the umlaut [for example, ü].)
In the early days of computers, all fonts were rendered from bitmaps. These bitmaps were carefully tweaked by typographers to present the best possible appearance for each font in each available size. A 12-point font was a distinctly different file from a 14-point font, and a bold font was different from a regular font. If you wanted a 14-point font and your system did not have a 14-point version of the font you wanted, you were out of luck. Windows 3.1 changed that for Windows users with the advent of TrueType fonts.
TrueType fonts are scalable outline fonts that make it possible to render any size font from a single font file. The file does not contain a bitmap, but rather instructions for creating the bitmap (many fonts still contain hand-tweaked bitmaps for the smaller sizes). These instructions include hints for optimizing the appearance over a wide range of sizes. Windows 2000 added support for OpenType fonts, an extension of TrueType technology that adds extended font-specific information.
|
With TrueType and OpenType fonts, you can specify any size font for either screen display or printer output, and the operating system will generate the correct bitmap. You can see which fonts are installed on a computer by going to Control Panel
Another way to classify fonts is by character width. In fixed pitch fonts, all characters, from the period to the lowercase i to the uppercase W, are the same width. These are the fonts of the typewriter and early impact printers. They are rarely used today, except for in the command line and for code listings. Fixed pitch fonts commonly found on Windows systems include Courier and Lucida Console.
The most commonly used fonts, both in the computer world and the real world, are proportional fonts. The lowercase i takes less horizontal space than the uppercase W. Typographers take great care to design proportional fonts to ensure that the characters flow smoothly. Kerning, the process of adjusting the whitespace between the characters, may vary depending on which letters are adjacent to one another. All this makes for easy reading and beautiful looking text, but it makes life difficult for the software developer who must know exactly how long a text string is so that subsequent characters or other graphic elements can be placed correctly. As you will see shortly, the .NET Framework solves this problem by providing the MeasureString method.
9.2.2 Font Class
Instances of the Font class define a specific font to be used for some text. This font definition includes the font family or typeface, such as Times New Roman or Arial, any style attributes, and the size.
9.2.2.1 Font properties
The Font object is immutable: all Font properties are read-only. If you want to change any of the properties of a Font object, then you must create a new Font object, using one of the thirteen available constructors and described shortly. However, one of the constructors lets you create a new Font object from an existing Font object while using a different set of styles.
Table 9-1 lists the commonly used properties of the Font class, all of which are read-only.
Property |
Value type |
Description |
---|---|---|
Bold |
Boolean |
Returns true if this font is bold. |
FontFamily |
FontFamily |
Returns a FontFamily object, i.e., a group of typefaces having a similar design. |
GdiCharSet |
Byte |
Returns the GDI character set for this font. |
GdiVerticalFont |
Boolean |
Returns true if this font derives from a GDI vertical font. |
Height |
Integer |
Returns the height of this font, in current graphics units. This is the recommended line spacing for the font for display on the video monitor. |
Italic |
Boolean |
Returns true if this font is italic. |
Name |
String |
Returns the name of the typeface for this font. |
Size |
Float (C#) Single (VB.NET) |
Returns the em size for this font, defined as the horizontal size equivalent to the point size of the font, in current design units. |
SizeInPoints |
Float /single |
Returns the size of this font, in points. |
Strikeout |
Boolean |
Returns true if this font has a horizontal line through it. |
Style |
FontStyle |
Returns one or more members of the FontStyle enumeration for this font. Members of the FontStyle enumeration are listed in Table 9-3. The values may be combined in a bitwise manner using the logical OR operator. |
Underline |
Boolean |
Returns true if this font is underlined. |
Unit |
GraphicsUnit |
Returns a member of the GraphicsUnit enumeration. Possible values are listed in Table 9-4. |
All controls have a Font property, of type Font, that specifies the typeface or design, size, and style, for any text displayed by the control.
Since the Font property is an ambient property, the current font for any child control is the same as the current font for the parent control, unless the child control explicitly sets it.
The default font for any form is determined by the Windows default font, which is set by going to Control Panel, and then the Display, selecting Properties and then the Settings tab. (You can get to the same Display dialog by right-clicking on the desktop and selecting Properties.) The specifics of each tab depend on the video driver installed on that system.
If the Font property of a control has been changed to something other than default, it can be set back to default in one of two ways: by setting the font equal to the static Control property DefaultFont or using the static Control method ResetFont.
The programs listed in Example 9-1 (in C#) and in Example 9-2 (in VB.NET) demonstrate many Font properties. They display a form with a label in one corner. A button captioned Show pops up a message box displaying various font properties of the Show button and the label. A second button, labeled Change, opens the Font common dialog box (covered in detail in Chapter 6) to let you change the font of the label.
Example 9-1. Font properties in C# (FontProperties.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class FontProperties : Form { private Button btnShow; private Button btnChange; private Label lbl; private FontDialog fd; public FontProperties( ) { Text = "Font Properties"; Size = new Size(350,200); btnShow = new Button( ); btnShow.Location = new Point(50,50); btnShow.Size = new Size(100,23); btnShow.Text = "Show"; btnShow.Click += new System.EventHandler(btnShow_Click); btnShow.Parent = this; btnChange = new Button( ); btnChange.Location = new Point(200,50); btnChange.Size = new Size(100,23); btnChange.Text = "Change"; btnChange.Click += new System.EventHandler(btnChange_Click); btnChange.Parent = this; lbl = new Label( ); lbl.Text = "The quick brown fox..."; lbl.AutoSize = true; lbl.Parent = this; } static void Main( ) { Application.Run(new FontProperties( )); } private void btnShow_Click(object sender, EventArgs e) { MessageBox.Show("Button Font: " + btnShow.Font.ToString( ) + " " + "Button Font Family: " + btnShow.Font.FontFamily.ToString( ) + " " + "Button Font Style: " + btnShow.Font.Style.ToString( ) + " " + "Button Font Unit: " + btnShow.Font.Unit.ToString( ) + " " + "Button Font Height: " + btnShow.Font.Height.ToString( ) + " " + "Label Font: " + lbl.Font.ToString( ) + " " + "Label Font Family: " + lbl.Font.FontFamily.ToString( ) + " " + "Label Font Style: " + lbl.Font.Style.ToString( ) + " " + "Label Font Unit: " + lbl.Font.Unit.ToString( ) + " " + "Label Font Height: " + lbl.Font.Height.ToString( ) + " ", "Font Properties"); } private void btnChange_Click(object sender, EventArgs e) { fd = new FontDialog( ); fd.ShowHelp = false; fd.ShowApply = true; fd.Apply += new System.EventHandler(this.fd_Apply); if (fd.ShowDialog( ) = = DialogResult.OK) lbl.Font = fd.Font; } private void fd_Apply(object sender, System.EventArgs e) { lbl.Font = fd.Font; } } }
Example 9-2. Font properties in VB.NET (FontProperties.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class FontProperties : inherits Form Private WithEvents btnShow as Button Private WithEvents btnChange as Button private lbl as Label private fd as FontDialog public sub New( ) Text = "Font Properties" Size = new Size(350,200) btnShow = new Button( ) btnShow.Location = new Point(50,50) btnShow.Size = new Size(100,23) btnShow.Text = "Show" btnShow.Parent = me btnChange = new Button( ) btnChange.Location = new Point(200,50) btnChange.Size = new Size(100,23) btnChange.Text = "Change" btnChange.Parent = me lbl = new Label( ) lbl.Text = "The quick brown fox..." lbl.AutoSize = true lbl.Parent = me end sub public shared sub Main( ) Application.Run(new FontProperties( )) end sub private sub btnShow_Click(ByVal sender as object, _ ByVal e as EventArgs) _ Handles btnShow.Click MessageBox.Show("Button Font: " + _ vbTab + btnShow.Font.ToString( ) + vbCrLf + _ "Button Font Family: " + vbTab + _ btnShow.Font.FontFamily.ToString( ) + vbCrLf + _ "Button Font Style: " + vbTab + _ btnShow.Font.Style.ToString( ) + vbCrLf + _ "Button Font Unit: " + vbTab + _ btnShow.Font.Unit.ToString( ) + vbCrLf + _ "Button Font Height: " + vbTab + _ btnShow.Font.Height.ToString( ) + vbCrLf + _ "Label Font: " + vbTab + _ lbl.Font.ToString( ) + vbCrLf + _ "Label Font Family: " + vbTab + _ lbl.Font.FontFamily.ToString( ) + vbCrLf + _ "Label Font Style: " + vbTab + _ lbl.Font.Style.ToString( ) + vbCrLf + _ "Label Font Unit: " + vbTab + _ lbl.Font.Unit.ToString( ) + vbCrLf + _ "Label Font Height: " + vbTab + _ lbl.Font.Height.ToString( ) + vbCrLf, _ "Font Properties") end sub private sub btnChange_Click(ByVal sender as object, _ ByVal e as EventArgs) _ Handles btnChange.Click fd = new FontDialog( ) fd.ShowHelp = false fd.ShowApply = true AddHandler fd.Apply, AddressOf fd_Apply if fd.ShowDialog( ) = DialogResult.OK then lbl.Font = fd.Font end if end sub private sub fd_Apply(ByVal sender As System.Object, _ ByVal e As System.EventArgs) lbl.Font = fd.Font End Sub end class end namespace
Class member variables are declared for each control on the form as well as the font common dialog. The label and button controls are instantiated and specified inside the constructor. No Size property is specified for the Label control; instead the AutoSize property is set to true. This will cause the Label to size itself automatically to accommodate its Text property.
When the Show button is clicked, the btnShow_Click event handler method is executed, which invokes a MessageBox that displays a variety of Font properties btnShow and the Label control.
Clicking on the Change button fires the btnChange_Click event handler, which displays the Font common dialog box. (Chapter 6 covers this dialog box in detail.) Since the ShowApply property of the dialog box is set to true, the Apply button is visible and operative on the dialog box. The Apply event raised by this button is handled by fd_Apply. The following appropriate line adds that method to the event delegate:
fd.Apply += new System.EventHandler(this.fd_Apply);
AddHandler fd.Apply, AddressOf fd_Apply
Running either program and changing the font to 16-point bold italic Comic Sans MS produces the form shown in Figure 9-1. Clicking on the Show button brings up the dialog shown in Figure 9-2.
Figure 9-1. Font Properties program
Figure 9-2. Font Properties dialog box
9.2.2.2 Constructors
There are 13 overloaded constructors for the Font class, the arguments of which are listed in Table 9-2, allowing for a wide range of needs. The simplest constructor lets you take an existing Font object and apply different styles. The remaining constructors are based on either a FontFamily object or a string representing a font family.
Constructor argument list |
Description |
---|---|
Font, FontStyle |
Instantiates a new font object, applying the specified styles from the FontStyle enumeration to an existing font object. Members of the FontStyle enumeration, which may be combined in a bitwise manner, are listed in Table 9-3. |
FontFamily, float (Single in VB.NET) |
Instantiates a new font object from the specified FontFamily object and of the specified size in points. |
string, float/Single |
Instantiates a new font object from the FontFamily named in the specified string and of the specified size in points. |
FontFamily, float/Single, FontStyle |
Instantiates a new font object from the specified FontFamily object, of the specified size in points, and with specified styles. |
string, float/Single, FontStyle |
Instantiates a new font object from the FontFamily named in the specified string, of the specified size in points, and with the specified styles. |
FontFamily, float/Single, GraphicsUnit |
Instantiates a new Font object from the specified FontFamily object, of the specified size, and with the unit of measurement specified by the GraphicsUnit. Valid members of the GraphicsUnit enumeration are listed in Table 9-4. |
string, float/Single, GraphicsUnit |
Instantiates a new Font object from the FontFamily named in the specified string, of the specified size, and with the unit of measurement specified by the GraphicsUnit. |
FontFamily, float/Single, FontStyle, GraphicsUnit |
Instantiates a new Font object from the specified FontFamily object, of the specified size, with the specified styles, and with the unit of measurement specified by the GraphicsUnit. |
string, float/Single, FontStyle, GraphicsUnit |
Instantiates a new Font object from the FontFamily named in the specified string, of the specified size, with the specified styles, and with the unit of measurement specified by the GraphicsUnit. |
FontFamily, float/Single, FontStyle, GraphicsUnit, byte |
Instantiates a new Font object from the specified FontFamily object, of the specified size, with the specified styles, with the unit of measurement specified by the GraphicsUnit, and the GDI character set specified by the byte argument. |
string, float/Single, FontStyle, GraphicsUnit, byte |
Instantiates a new Font object from the FontFamily named in the specified string, of the specified size, with the specified styles, with the unit of measurement specified by the GraphicsUnit, and the GDI character set specified by the byte argument. |
FontFamily, float/Single, FontStyle, GraphicsUnit, byte, bool |
Instantiates a new Font object from the specified FontFamily object, of the specified size, with the specified styles, with the unit of measurement specified by the GraphicsUnit, the GDI character set specified by the byte argument, and a Boolean value of true if the new Font object is derived from a GDI vertical font. |
string, float/Single, FontStyle, GraphicsUnit, byte, bool |
Instantiates a new Font object from the FontFamily named in the specified string, of the specified size, with the specified styles, with the unit of measurement specified by the GraphicsUnit, the GDI character set specified by the byte argument, and a Boolean value of true if the new Font object is derived from a GDI vertical font. |
|
Member |
---|
Value |
Regular |
Bold |
Italic |
Strikeout |
Underline |
Member |
Unit of measure |
---|---|
Display |
1/75 inch (raises an exception when used with Font) |
Document |
1/300 inch |
Inch |
1 inch |
Millimeter |
1 millimeter |
Pixel |
1 device pixel |
Point |
1/72 inch |
World |
world unit |
The next several examples demonstrate some commonly used constructors. All the constructor examples will be based on the same simple form. It displays a multiline text string in the Text property of a RichTextBox control. (RichTextBox controls are covered in detail in Chapter 12.) Since the Font property of a control is an ambient property, the RichTextBox will inherit its Font property from the form. In the form constructor, the Font constructor will set the current font for the form.
The rich text box control in these examples displays two lines of static text followed by several lines displaying current font properties.
|
9.2.2.2.1 Constructor based on existing font and FontStyles
Example 9-3 (in C#) and Example 9-4 (in VB.NET) use the font constructor based on an existing Font object. The highlighted lines of code show the usage of the font constructor. Since this form of the constructor needs to base itself on an existing Font object, the first line of highlighted code creates that object from the default font of the form.
Example 9-3. Font constructor based on existing font in C# (FontConstructor1.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class FontConstructor1 : Form { public FontConstructor1( ) { Text = "Font Constructor"; Size = new Size(350,200); // Font constructor stuff Font fnt = Font; fnt = new Font(fnt, FontStyle.Bold | FontStyle.Italic); Font = fnt; // End of font constructor stuff RichTextBox rtxt = new RichTextBox( ); rtxt.Text = "The quick brown fox jumps over the lazy dog. " + "This is a second line of text."; rtxt.Text += " Font Name: " + Font.Name; rtxt.Text += " Font Family: " + Font.FontFamily; rtxt.Text += " Font Styles: " + Font.Style; rtxt.Text += " Font Size: " + Font.Size; rtxt.Text += " Font Height: " + Font.Height; rtxt.Text += " Font Units: " + Font.Unit; rtxt.Multiline = true; rtxt.Dock = DockStyle.Fill; rtxt.Parent = this; } static void Main( ) { Application.Run(new FontConstructor1( )); } } }
Example 9-4. Font constructor based on existing font in VB.NET (FontConstructor1.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class FontConstructor1 : inherits Form public sub New( ) Text = "Font Constructor" Size = new Size(350,200) ' Font constructor stuff dim fnt as Font = Font fnt = new Font(fnt, FontStyle.Bold or FontStyle.Italic) Font = fnt ' End of font constructor stuff dim rtxt as new RichTextBox( ) rtxt.Text = "The quick brown fox jumps over the lazy dog." + vbCrLf + _ "This is a second line of text." rtxt.Text += vbCrLf + "Font Name:" + vbTab + Font.Name rtxt.Text += vbCrLf + "Font Family:" + vbTab + _ Font.FontFamily.ToString( ) rtxt.Text += vbCrLf + "Font Styles:" + vbTab + Font.Style.ToString rtxt.Text += vbCrLf + "Font Size:" + vbTab + Font.Size.ToString( ) rtxt.Text += vbCrLf + "Font Height:" + vbTab + Font.Height.ToString( ) rtxt.Text += vbCrLf + "Font Units:" + vbTab + Font.Unit.ToString( ) rtxt.Multiline = true rtxt.Dock = DockStyle.Fill rtxt.Parent = me end sub public shared sub Main( ) Application.Run(new FontConstructor1( )) end sub end class end namespace
The middle highlighted line of code is the actual Font constructor. It takes two arguments: an existing Font object and one or more FontStyles. The FontStyles are combined in a bitwise manner using the logical OR operator. The third line of highlighted code then assigns the new Font object back to the Form's current font.
When this example is compiled and run, it results in the form shown in Figure 9-3.
Figure 9-3. Font constructor based on existing font.
9.2.2.2.2 Constructor based on FontFamily and size
The next several code snippets demonstrate two different constructors based on the font family name and a font size. The first version takes a string containing the name of a font family as an argument, along with the size of the font in points.
The font family name must correspond exactly to one of the installed font families on your system. The easiest way to see what font families are on a machine is to open a font dialog from WordPad and look through the font drop-down list. (An example presented shortly will show how to find all the font families installed on a system programmatically.)
If the font family is not installed on the system or the name is misspelled, no exception will be thrown, but the font will revert to the default Windows font, Microsoft Sans Serif. The font name string is not case sensitive. Even in C# "times new roman" is the same as "Times New Roman."
To use this constructor, replace the highlighted lines of C# code in Example 9-3, reproduced here:
Font fnt = Font; fnt = new Font(fnt, FontStyle.Bold | FontStyle.Italic); Font = fnt;
with the following lines of code:
Font fnt = new Font("Times New Roman", 10); fnt = new Font(fnt, FontStyle.Bold | FontStyle.Italic); Font = fnt;
or the highlighted VB.NET lines in Example 9-4, reproduced here:
dim fnt as Font = Font fnt = new Font(fnt, FontStyle.Bold or FontStyle.Italic) Font = fnt
with these lines:
dim fnt as new Font("Times New Roman", 10) fnt = new Font(fnt, FontStyle.Bold or FontStyle.Italic) Font = fnt
This will cause the form font to be 10-point Bold Italic Times New Roman.
Another version of the constructor takes a FontFamily object rather than the name of the font family in a string. There are several ways to get a FontFamily object. The simplest FontFamily constructor takes a string with the name of the family:
FontFamily ffTNR = new FontFamily("Times New Roman");
dim ffTNR as new FontFamily("Times New Roman")
You can create generic font families by using members of the GenericFontFamilies enumeration, listed in Table 9-5, as the argument to the FontFamily constructor.
Value |
Description |
---|---|
Monospace |
Generic fixed-pitch FontFamily object |
SansSerif |
Generic sans serif FontFamily object |
Serif |
Generic serif FontFamily object |
The programs listed in Example 9-5 and Example 9-6 each use the same form as the previous example, but here the rich text box is populated with a list of all the font families installed on the system that have a regular font.
Example 9-5. Font families in C# (FontFamiles.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class FontFamilies : Form { public FontFamilies( ) { Text = "Font Families"; Size = new Size(350,200); RichTextBox rtxt = new RichTextBox( ); rtxt.Multiline = true; rtxt.Dock = DockStyle.Fill; rtxt.Parent = this; FontFamily[ ] ffArray = FontFamily.Families; foreach( FontFamily ff in ffArray ) { if (ff.IsStyleAvailable(FontStyle.Regular)) { rtxt.Text += ff.Name + " "; } } } static void Main( ) { Application.Run(new FontFamilies( )); } } }
Example 9-6. Font families in VB.NET (FontFamiles.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class FontFamilies : inherits Form public sub New( ) Text = "Font Families" Size = new Size(350,200) dim rtxt as new RichTextBox( ) rtxt.Multiline = true rtxt.Dock = DockStyle.Fill rtxt.Parent = me dim ffArray as FontFamily( ) = FontFamily.Families dim ff as FontFamily for each ff in ffArray if ff.IsStyleAvailable(FontStyle.Regular) then rtxt.Text += ff.Name + vbCrLf end if next end sub public shared sub Main( ) Application.Run(new FontFamilies( )) end sub end class end namespace
In Example 9-5 and Example 9-6, after the RichTextBox object is instantiated, an array of FontFamily objects is created using the static property Families of the FontFamily class.
The array is iterated using a foreach loop (For Each in VB.NET), adding each FontFamily name to the Text property of the rich text box.
Here is the tricky part: you must verify that a FontFamily has a regular memberi.e., a member that is neither bold nor italicbefore trying to create it. The style verification is performed using the IsStyleAvailable method of the FontFamily class. This is necessary because the default font style is FontStyle.Regular. Therefore, the Font constructor using the FontFamily object will try to create a regular font. If a regular member of the font family does not exist, an exception is thrown.
|
Assuming a regular style exists for the family, a new 10-point Font object is instantiated in that font family and it's Name property is added to the rich text box's Text property.
The result is shown in Figure 9-4.
Figure 9-4. Font families
9.2.2.2.3 Constructor based on FontFamily, size, and FontStyles
Two Font constructors take three arguments: a font family, the size in points, and a bitwise combination of FontStyles. The font family can be either a FontFamily object or a string representing a font family.
Using the programs listed in Example 9-3 and Example 9-4 as test beds, replace the highlighted code with this code snippet:
FontFamily ff = new FontFamily("Times New Roman"); Font fnt = new Font(ff, 12, FontStyle.Bold | FontStyle.Italic); Font = fnt;
dim ff as new FontFamily("Times New Roman") dim fnt as new Font(ff, 12, FontStyle.Bold or FontStyle.Italic) Font = fnt
These code snippets declare a FontFamily object representing Times New Roman. The Font constructor is then invoked, passing that FontFamily object, the size (12 points), and a combination of Bold and Italic FontStyles. The result is shown in Figure 9-5.
Figure 9-5. Font constructor based on font family, size, and styles
An alternative form of the font constructor takes a string representing the font family rather than a FontFamily object. Thus, the following C# code snippet would have the same results (VB.NET is analogous):
Font fnt = new Font("Times New Roman", 12, FontStyle.Bold | FontStyle.Italic); Font = fnt;
9.2.2.2.4 Constructor based on FontFamily, size, and GraphicsUnit
Another pair of Font constructors takes three arguments: a font family (either an object or a string), a size, and a GraphicsUnit value that specifies the units to use for the size. Valid values for the GraphicsUnit argument are members of the GraphicsUnit enumeration, listed in Table 9-4. The following code snippets, replacing the highlighted code from Example 9-3 and Example 9-4, cause the form font to be 1/4-inch Times New Roman approximately equivalent to 18 point:
FontFamily ff = new FontFamily("Times New Roman"); Font fnt = new Font(ff, .25f, GraphicsUnit.Inch); Font = fnt;
dim ff as new FontFamily("Times New Roman") dim fnt as new Font(ff, .25f, GraphicsUnit.Inch) Font = fnt
The resulting form, resized to fit all the text, is shown in Figure 9-6.
Figure 9-6. Font constructor based on font family, size, and GraphicUnit
9.2.2.2.5 Constructor based on FontFamily, size, FontStyles, and GraphicsUnit
The final pair of Font constructors examined in detail is similar to the previous two pairs, except they take both a FontStyles argument and a GraphicsUnit argument to specify the units for the size.
The following code snippets would create an Arial Bold Italic font, 1/2-inch in size:
FontFamily ff = new FontFamily("Arial"); Font fnt = new Font(ff, .5f, FontStyle.Bold | FontStyle.Italic, GraphicsUnit.Inch); Font = fnt;
dim ff as new FontFamily("Arial") dim fnt as new Font(ff, .5f, FontStyle.Bold or FontStyle.Italic, _ GraphicsUnit.Inch) Font = fnt
9.2.2.3 Line spacing
The vertical space between lines of text is called leading (in the old days of physical type, you would put extra space between lines by adding a plain piece of lead). If two lines of 12-point text are spaced 12 points apart, then there is no leading. Text set this way will appear dense and difficult to read. This is especially true if there are a lot of upper case letters and/or diacritical marks.
Typographers note the size of the text and the leading together, so the earlier example would be written as 12/12. If two points of space are added between the lines, then it would become 12/14. Typographers, graphic artists, and page layout editors put a great deal of effort into adjusting the vertical spacing of lines of text to suit the material being displayed.
The .NET Framework provides two different techniques for determining the vertical line spacing of a font. There are no Font properties or methods provided to set the line spacing explicitly. In multiline text box controls, the line spacing is automatically set by the font and the control. You can control the line spacing if you draw the text strings directly to a graphics object (discussed later in Chapter 10).
Both the Height property and the GetHeight method return the recommended line spacing, in current units, of the Font object. The value returned by the Height property is applicable only when using the default page transform on the video display. The GetHeight method, on the other hand, has one overloaded form (out of three) that takes a Graphics object as an argument. By knowing the Graphics object, it also knows the current page transform and the device resolution, so it is able to give the correct line spacing for all situations, both on the video display and the printer.
|
9.2.3 Drawing Strings
All the examples so far in this chapter have displayed text by using a control's Text property. You can also draw strings directly onto the client area of a form or other control by using a Graphics object and the Paint event.
Chapter 10 will cover graphics and drawing more thoroughly. This section only introduces enough about the Graphics object in order to explain how to draw and use strings.
A Graphics object provides a surface to draw on. There are several ways to obtain a Graphics object. The technique used in this section adds an event handler to the Paint event delegate and then extracts the Graphics object from the PaintEventArgs event argument that is passed to the handler when the event is raised. This will be clarified shortly with an example.
9.2.3.1 DrawString( )
The DrawString method of the Graphics class draws text strings. It has six overloaded forms, the arguments of which are listed in Table 9-6.
Arguments |
Description |
---|---|
string, Font, Brush, float (Single in VB.NET), float/Single |
Draw the specified string, using the specified Font and Brush objects, located such that the upper-left corner of the text is located at the X and Y coordinates indicated by the two numbers, respectively. |
string, Font, Brush, PointF |
Draw the specified string, using the specified Font and Brush objects, located such that the upper-left corner of the text is located at the specified PointF coordinates. |
string, Font, Brush, RectangleF |
Draw the specified string, using the specified Font and Brush objects, in the specified RectangleF object. |
string, Font, Brush, float/Single, float/Single, StringFormat |
Draw the specified string, using the specified Font and Brush objects, at a location indicated by X and Y coordinates of the upper-left corner of the text, using the specified StringFormat object (described later in this chapter in Section 9.2.3.2). |
string, Font, Brush, PointF, StringFormat |
Draw the specified string, using the specified Font and Brush objects at the specified PointF coordinates, using the specified StringFormat object (described later in this chapter in Section 9.2.3.2). |
string, Font, Brush, RectangleF, StringFormat |
Draw the specified string, using the specified Font and Brush objects in the specified RectangleF object, using the specified StringFormat object (described later in this chapter in Section 9.2.3.2). |
The programs listed in Example 9-7 and Example 9-8 demonstrate how to use the DrawString method to draw on the client area of the form the name of each font family that has a regular style installed on the system. Example 9-7 and Example 9-8 are similar to Example 9-5 and Example 9-6, except that the text is drawn directly on the form; there is no rich text box control. Creating the form is the only work done in the constructor of the form. All the heavy lifting occurs in the overridden OnPaint event handler method.
Example 9-7. Drawing FontFamilies in C# (DrawFontFamilies.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class DrawFontFamilies : Form { public DrawFontFamilies( ) { Text = "Drawn Font Families"; Size = new Size(350,200); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); float x= 10; float y= 10; Font fnt; Graphics g = e.Graphics; FontFamily[ ] ffArray = FontFamily.Families; foreach( FontFamily ff in ffArray ) { if (ff.IsStyleAvailable(FontStyle.Regular)) { fnt = new Font(ff, 10); g.DrawString(ff.Name, fnt, Brushes.Black, x, y); y += fnt.GetHeight( ); } } } static void Main( ) { Application.Run(new DrawFontFamilies( )); } } }
Example 9-8. Drawing FontFamilies in VB.NET (DrawFontFamilies.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class DrawFontFamilies : inherits Form public sub New( ) Text = " Drawn Font Families" Size = new Size(350,200) end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim x as single = 10 dim y as single = 10 dim fnt as Font dim g as Graphics = e.Graphics dim ffArray as FontFamily( ) = FontFamily.Families dim ff as FontFamily for each ff in ffArray if ff.IsStyleAvailable(FontStyle.Regular) then fnt = new Font(ff, 10) g.DrawString(ff.Name, fnt, Brushes.Black, x, y) y += fnt.GetHeight( ) end if next end sub public shared sub Main( ) Application.Run(new DrawFontFamilies( )) end sub end class end namespace
The overridden OnPaintevent handler method has an event argument of type PaintEventArgs, which has two read-only properties: ClipRectangle and Graphics. ClipRectangle defines a rectangle in which to paint. The Graphics property returns a Graphics object, which in turn exposes the DrawString method.
Within OnPaint, several objects are initialized, including:
- Two numbers (float in C#, Single in VB.NET), which will be used to locate the text strings on the drawing surface
- A Font object
- A Graphics object
An array of font families is instantiated and iterated as shown in Example 9-5 and Example 9-6, except that the text string buildup is replaced with a call to DrawString and the vertical coordinate is incremented by the preferred line spacing returned from the GetHeight( ) method.
When the program is compiled and run, you will get something similar to Figure 9-7, after the form is resized to eliminate the vertical scrollbar.
Figure 9-7. Drawn font families
The call to DrawString takes five arguments:
g.DrawString(ff.Name, fnt, Brushes.Black, x, y);
The first argument is the text string to draw, in this case the name of the FontFamily. The second argument is a Font object to use for the text string. On each iteration through the loop, the Font object is reset to the next available font family at 10 points. The next argument is a Brush object, which will be covered shortly. The final two arguments are the horizontal and vertical coordinates, in current units, of the top-left corner of the text string.
9.2.3.2 Brush and brushes
Brush is an abstract (MustInherit in VB.NET) class in the System.Drawing namespace. A Brush object fills the interior spaces of graphical shapes. Five different classes are derived from Brush, as listed in Table 9-7.
Class |
Description |
---|---|
HatchBrush |
A brush that fills a graphical shape with a hatch style from the HatchStyle enumeration, such as BackwardDiagonal, DarkVertical, Divot, and Percent60. The ForegroundColor property gets the color of the lines and the BackgroundColor property gets the color of the space behind the lines. |
LinearGradientBrush |
A brush with a linear gradient. Properties such as Blend, GammaCorrection, and Transform let you control the resulting appearance. |
PathGradientBrush |
A brush that fills a graphical shape with a gradient. Properties such as Blend, CenterColor, and Transform allow programmatic interaction with the resulting appearance. |
SolidBrush |
A brush that fills a graphical shape with a color. Valid colors are either members of the Color structure, which has members such as Color.Brown, Color.Crimson, and Color.PaleGoldenrod, or a custom color you create. Appendix A contains the complete list of standard colors. Chapter 10 describes the Color structure. |
TextureBrush |
A brush that fills a graphical shape with a texture. The texture can come from an Image object, either a bitmap or a metafile. |
For easy access to the colored brushes, you can use a Brushes class (note the plural), which contains only static (Shared in VB.NET), read-only properties of type Brush corresponding to each of the standard colors, such as Brushes.Black, Brushes.DarkGoldenrod, and Brushes.WhiteSmoke. This Brushes class provides the Brush object used in the DrawString call in Example 9-7 and Example 9-8.
The form shown in Figure 9-7 looks fine on my system, and may look fine on yours, but what happens if the user has changed the Windows color scheme so that the form has a dark or black background? One way to avoid this problem is to set your SolidBrush to use the current ForeColor of the form, and then use that SolidBrush as the Brush object in the call to DrawString, as in:
Brush b = new SolidBrush(ForeColor); g.DrawString(ff.Name, fnt, b, (int)x, (int)y);
dim b as Brush = new SolidBrush(ForeColor) g.DrawString(ff.Name, fnt, b, CInt(x), CInt(y))
9.2.3.3 Formatting and alignment
Several overloaded versions of the DrawString method take an object of type StringFormat as one of the arguments. The StringFormat class has properties that provide horizontal and vertical text alignment, automatic insertion of ellipsis characters if the string exceeds its allotted space, and other formatting features. Commonly used StringFormat properties are listed in Table 9-8.
Property |
Type |
Description |
---|---|---|
Alignment |
StringAlignment |
Read/write. Provides horizontal alignment of text strings relative to the location point of the string or the containing rectangle. Valid values are members of the StringAlignment enumeration, listed in Table 9-9. |
FormatFlags |
StringFormatFlags |
Read/write. Valid values are a bitwise combination of members of the StringFormatFlags enumeration, listed in Table 9-10. |
HotkeyPrefix |
HotkeyPrefix |
Read/write. Controls underline mode of characters following an ampersand (&) character. Valid values are members of HotkeyPrefix enumeration: if Hide, the character following the ampersand is not underlined and the ampersand is not displayed; if Show, the character after the ampersand is underlined; if None, the ampersand is displayed and nothing is underlined. If set to HotkeyPrefix.Show, you must still provide an event handler to implement the keyboard shortcut. |
LineAlignment |
StringAlignment |
Read/write. Provides vertical alignment of text strings relative to the location point of the string or the containing rectangle. Valid values are members of the StringAlignment enumeration, listed in Table 9-9. |
Trimming |
StringTrimming |
Read/write. Specifies how to trim characters if the text exceeds the bounds of the layout rectangle. Valid values are members of the StringTrimming enumeration, listed in Table 9-11. |
Value |
Description |
---|---|
Center |
Text is center-aligned. For both horizontal alignment (Alignment property) and vertical alignment (LineAlignment property), the center of the string will be at the location point or in the center of the layout rectangle. |
Near |
For horizontal alignment of left-to-right text, this value will be left-aligned relative to the location point or rectangle. For right-to-left text, it will be right-aligned. For vertical alignment, it will be bottom-aligned relative to the location point or rectangle. |
Far |
For horizontal alignment of left-to-right text, it will be right-aligned relative to the location point or rectangle. For right-to-left text, it will be left-aligned. For vertical alignment, the value will be top-aligned relative to the location point or rectangle. |
Value |
Description |
---|---|
DirectionRightToLeft |
Text is right to left. |
DirectionVertical |
Text is vertical. |
DisplayFormatControl |
Displays control characters in the output. |
FitBlackBox |
None of the characters overhang the bounding rectangle. |
LineLimit |
Only entire lines are visible. |
MeasureTrailingSpaces |
Forces MeasureString method to include trailing spaces. |
NoClip |
Characters and unwrapped text may exceed the bounding rectangle. |
NoFontFallback |
Disables display of alternate font if the requested font is not available. |
NoWrap |
Disables line wrapping. |
Value |
Description |
---|---|
Character |
Text is trimmed to the nearest character. |
EllipsisCharacter |
Text is trimmed to the nearest character and an ellipsis is inserted the end of the trimmed line. |
EllipsisPath |
The center of the trimmed line is removed and replace by an ellipsis. If the text includes a path, as much of the last slash-delimited segment is retained as possible. |
EllipsisWord |
Text is trimmed to the nearest word and an ellipsis is inserted the end of the trimmed line. |
None |
No trimming occurs. |
Word |
Text is trimmed to nearest word. |
The programs listed in Example 9-9 and Example 9-10 demonstrate the use of the Alignment StringFormat property. In these code listings, the Alignment value of the StringFormat property is set to Center. The result can be seen in the middle image in Figure 9-8. If the value had been set to Near, the text strings would have been left justified against the location point, as seen in the left-most image in Figure 9-8, and if the value had been set to Far, the text strings would have been right justified against the location point, as seen in the right-most image in Figure 9-8.
|
Example 9-9. DrawString method with Alignment in C# (DrawFontFamiliesFormatted.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class DrawFontFamiliesFormatted : Form { public DrawFontFamiliesFormatted( ) { Text = "Drawn Font Families Formatted"; Size = new Size(350,200); ResizeRedraw = true; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); float y= 10; Font fnt; Graphics g = e.Graphics; StringFormat fmt = new StringFormat( ); fmt.Alignment = StringAlignment.Center; FontFamily[ ] ffArray = FontFamily.Families; foreach( FontFamily ff in ffArray ) { if (ff.IsStyleAvailable(FontStyle.Regular)) { fnt = new Font(ff, 10); Brush b = new SolidBrush(ForeColor); g.DrawString(ff.Name, fnt, b, ClientSize.Width / 2, (int)y, fmt); y += fnt.GetHeight( ); } } } static void Main( ) { Application.Run(new DrawFontFamiliesFormatted( )); } } }
Example 9-10. DrawString method with Alignment in VB.NET (DrawFontFamiliesFormatted.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class DrawFontFamiliesFormatted : inherits Form public sub New( ) Text = "Drawn Font Families Formatted" Size = new Size(350,200) ResizeRedraw = true end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim y as single = 10 dim fnt as Font dim g as Graphics = e.Graphics dim fmt as new StringFormat( ) fmt.Alignment = StringAlignment.Center dim ffArray as FontFamily( ) = FontFamily.Families dim ff as FontFamily for each ff in ffArray if ff.IsStyleAvailable(FontStyle.Regular) then fnt = new Font(ff, 10) dim b as Brush = new SolidBrush(ForeColor) g.DrawString(ff.Name,fnt,b,CInt(ClientSize.Width / 2),CInt(y),fmt) y += fnt.GetHeight( ) end if next end sub public shared sub Main( ) Application.Run(new DrawFontFamiliesFormatted( )) end sub end class end namespace
Figure 9-8. Alignment StringFormat property: Near, Center, and Far (left to right)
In Example 9-9 and Example 9-10, the Brush object is instantiated as a SolidBrush by using the ForeColor property, so it will be visible irrespective of the color scheme chosen by the user.
In the call to the DrawString method, the horizontal location of the string is set to one half of the width of the client area of the form; this allows you to center the strings in the center of the form.
Inside the constructor you set the ResizeRedraw property to true. Doing so forces the form to invalidate and redraw the client area every time the form is resized by the user, eliminating artifacts left behind when the form is resized.
In Example 9-11 and Example 9-12, a simple form is created with a button and a text string drawn on the client area. The button is labeled "Do It!" The Alt-D keyboard shortcut is implemented by adding an ampersand to the Text property of the button. The resulting form is shown in Figure 9-9.
Example 9-11. DrawString with HotkeyPrefix StringFormat property in C# (DrawStringHotkey.cs)
using System; using System.Drawing; using System.Windows.Forms; using System.Drawing.Text; // necessary for HotkeyPrefix namespace ProgrammingWinApps { public class DrawStringHotkey : Form { public DrawStringHotkey( ) { Text = "DrawString Hotkey"; Size = new Size(350,200); ResizeRedraw = true; Button btn = new Button( ); btn.Parent = this; btn.Text = "&Do It!"; btn.Location = new Point((ClientSize.Width / 2) - (btn.Width / 2), ClientSize.Height / 2); btn.Click += new EventHandler(btn_Click); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; StringFormat fmt = new StringFormat( ); fmt.Alignment = StringAlignment.Center; fmt.HotkeyPrefix = HotkeyPrefix.Show; Brush b = new SolidBrush(ForeColor); g.DrawString("&Do It!", Font, b, ClientSize.Width / 2, 50, fmt); } private void btn_Click(object sender, EventArgs e) { MessageBox.Show("Now you've done it."); } static void Main( ) { Application.Run(new DrawStringHotkey( )); } } }
Example 9-12. DrawString with HotkeyPrefix StringFormat property in VB.NET (DrawStringHotkey.vb)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms imports System.Drawing.Text ' necessary for HotkeyPrefix namespace ProgrammingWinApps public class DrawStringHotkey : inherits Form public sub New( ) Text = "Drawn Font Families Formatted" Size = new Size(350,200) ResizeRedraw = true dim btn as new Button( ) btn.Parent = me btn.Text = "&Do It!" btn.Location = new Point(CInt((ClientSize.Width / 2)) - _ CInt((btn.Width / 2)), _ CInt(ClientSize.Height / 2)) AddHandler btn.Click, AddressOf btn_Click end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim g as Graphics = e.Graphics dim fmt as new StringFormat( ) fmt.Alignment = StringAlignment.Center fmt.HotkeyPrefix = HotkeyPrefix.Show dim b as Brush = new SolidBrush(ForeColor) g.DrawString("&Do It!", Font, b, Cint(ClientSize.Width / 2), 50, fmt) end sub private sub btn_Click(ByVal sender as object, _ ByVal e as EventArgs) MessageBox.Show("Now you've done it.") end sub public shared sub Main( ) Application.Run(new DrawStringHotkey( )) end sub end class end namespace
Figure 9-9. HotkeyPrefix StringFormat property
First, note that you must add a reference to the System.Drawing.Text namespace for the HotkeyPrefix to work:
using System.Drawing.Text;
imports System.Drawing.Text
The button control is instantiated in the constructor and its Location property is set so that it is centered in the form. The Text property has an ampersand before the D; this causes the D to be underlined and automatically implements the keyboard shortcut. An event handler is added for the Click event. The event handler method in this example simply puts up a message box.
In the PaintHandler method, two properties are set for the StringFormat object: the Alignment property is set to Center and the HotkeyPrefix property is set to Show. Then in the string argument of DrawString, an ampersand is inserted just before the D, causing that character to be underlined.
Underlining the character via the DrawString method does not implement any keyboard shortcuts or key event handling. That must be done using other techniques. This example uses the Button keyboard shortcut. You could also use key event handling described in Chapter 4 or the menu keyboard shortcuts described in Chapter 18.
9.2.4 Measuring Strings
In Chapter 7, several examples were presented that sized a control based on the estimated size of its Text property. This estimate was arrived at by multiplying the number of characters in the string by the Font.Height property and by an arbitrary "fudge factor." The MeasureString method of the Graphics class provides a much more elegant and precise (although it will not be perfectly precise unless using anti-aliased text) way of measuring the length and height of a text string, taking into account the actual Font object used to draw the string.
The MeasureString method has several overloaded forms. All the forms return a SizeF structure that represents the size of the string in pixels. The basic form takes two arguments: the string to measure and the Font object with which to draw the string. All the other forms take those same two arguments, plus additional arguments that force line wrapping, take formatting into account, and so on.
|
For a string consisting of a single line of text, the value of SizeF.Height will be the same as the value returned by the Font.GetHeight method. However, if the text string contains NewLine or LineFeed characters, or if one of the overloaded versions of MeasureString is used, which forces a line wrap, then SizeF.Height will reflect the actual size of the text block.
Table 9-12 lists the argument lists for each overloaded form.
Arguments |
Description |
---|---|
string, Font |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object. |
string, Font, integer |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object. Integer is the maximum width of the SizeF structure, in pixels; if the string will not fit within this width, it will wrap and the height of the returned SizeF structure will reflect the size with the actual number of lines. |
string, Font, SizeF |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object. SizeF structure is the maximum size, in pixels, of the string's layout area. |
string, Font, integer, StringFormat |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object, using specified StringFormat properties. Integer is the maximum width of the SizeF structure, in pixels; if the string will not fit within this width, it will wrap and the height of the returned SizeF structure will reflect the size with the actual number of lines. |
string, Font, PointF, StringFormat |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object, with its upper-left corner located at the point described by the PointF structure, using the specified StringFormat properties. |
string, Font, SizeF, StringFormat |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object, using the specified StringFormat properties. SizeF structure is the maximum size, in pixels, of the string's layout area. |
string, Font, SizeF, StringFormat, integer, integer |
Returns SizeF structure, in pixels, of the specified string drawn with the specified Font object, using the specified StringFormat properties. SizeF structure is the maximum size, in pixels, of the string's layout area. The first integer argument is the number of characters in the string, and the second integer argument is the number of lines of text. |
The examples listed in Example 9-13 and Example 9-14, based on the previous examples, demonstrate the use of the MeasureString method. In these examples, a button displays the results of measuring a sample string drawn on the form. MeasureString is also used in the Analog Clock project shown in Chapter 10.
Example 9-13. MeasureString method in C# (StringMeasure.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class StringMeasure : Form { SizeF sz = new SizeF( ); public StringMeasure( ) { Text = "Measure String"; Size = new Size(350,200); Button btn = new Button( ); btn.Parent = this; btn.Text = "&Measure"; btn.Location = new Point((ClientSize.Width / 2) - (btn.Width / 2), ClientSize.Height / 2); btn.Click += new EventHandler(btn_Click); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); string str = "The quick brown fox jumped..."; PointF pt = new PointF(ClientSize.Width / 2, 50); Graphics g = e.Graphics; StringFormat fmt = new StringFormat( ); fmt.Alignment = StringAlignment.Center; Brush b = new SolidBrush(ForeColor); g.DrawString(str, Font, b, pt, fmt); sz = g.MeasureString(str,Font, pt, fmt); } private void btn_Click(object sender, EventArgs e) { MessageBox.Show("The string size is " + sz.ToString( )); } static void Main( ) { Application.Run(new StringMeasure( )); } } }
Example 9-14. MeasureString method in VB.NET (StringMeasure.cs)
Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class StringMeasure : inherits Form dim sz as new SizeF( ) public sub New( ) Text = "Drawn Font Families Formatted" Size = new Size(350,200) dim btn as new Button( ) btn.Parent = me btn.Text = "&Measure" btn.Location = new Point(CInt((ClientSize.Width / 2)) - _ CInt((btn.Width / 2)), _ CInt(ClientSize.Height / 2)) AddHandler btn.Click, AddressOf btn_Click end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim str as String = "The quick brown fox jumped..." dim pt as new PointF(CInt(ClientSize.Width / 2), 50) dim g as Graphics = e.Graphics dim fmt as new StringFormat( ) fmt.Alignment = StringAlignment.Center dim b as Brush = new SolidBrush(ForeColor) g.DrawString(str, Font, b, pt, fmt) sz = g.MeasureString(str,Font, pt, fmt) end sub private sub btn_Click(ByVal sender as object, _ ByVal e as EventArgs) MessageBox.Show("The string size is " + sz.ToString( )) end sub public shared sub Main( ) Application.Run(new StringMeasure( )) end sub end class end namespace
In the programs listed in Example 9-13 and Example 9-14, a class member variable of type SizeF is declared. This variable will store the return value of the MeasureString method in the PaintHandler method, and then display the size in the btn_Click method.
In the PaintHandler method, two additional variables are declared: a string that draws and measures, and a PointF variable that holds the location of the text string on the graphics surface. The latter variable is necessary because the only variants of the MeasureString method that take a StringFormat argument also require either some sort of size indicator or a location parameter, hence the PointF. If your DrawString method uses a StringFormat argument, it is wise to use the same StringFormat argument when measuring the string.