We
now turn our attention to the subject of fonts. Font selection is the
primary way to control text appearance. Windows CE supports two basic
font methods: bitmap fonts and TrueType (also known as OpenType, for
PostScript compatibility) fonts. A given platform can support one but
not both of these font types. The decision about which to support is
made by the platform creator and cannot be changed by an application
program. Some platforms support bitmap fonts to minimize the size of
the operating system image. The benefits of supporting TrueType fonts
include the ability to draw scalable fonts and the ability to draw
rotated text.
What
font support is found on Windows mobile devices? Windows Mobile
Professional (Pocket PC) supports TrueType fonts, and has these built
in: Tahoma, Courier New and Bookdings. Windows Mobile Standard (Smartphone) also supports TrueType fonts and has a single built-in font: Segoe Condensed.
1. The Font Property of Controls
The built-in controls use fonts. As shown in Figure 1,
you select a control’s font at design time in the Properties window of
the Designer provided as part of Visual Studio. A word of caution is in
order: The Designer cannot know what fonts are installed on your
Windows Mobile device, so it provides a best guess. For example, when
using an SDK for a Smartphone, you will see a choice of two fonts: Nina
and Segoe Condensed. This is a pretty good guess, because Nina is the
name of the font on older Smartphones, and the other name is on the
newer ones.
However,
a given device might have more fonts than these. You can, for example,
add fonts to a Windows Mobile device by copying font files to the
\Windows\Fonts folder. If you install new fonts when you install your
application, you can list those for use in a control. Just remember
that Visual Studio has no way to know which specific fonts you have
installed.
Font
support in Windows CE—as in desktop Windows—uses a process that is
sometimes called font mapping. This process takes a request for a font
and tries to map that request to a font that is actually present in the
system. It works best when the font name or font family is present and
when the size you request is available. It fails when either of these
conditions is not met; in such situations this feature is sometimes
called font mangling. The solution is to make sure you request font
names and sizes that are available on the device.
As shown in the SimpleDrawString sample program, you can draw in a form or in a control by accessing the Font property of the form or control.
Here is the line of code that shows this being done:
e.Graphics.DrawString("Simple Draw String", Font, brText,
xDraw, yDraw);
The Font
property is a read/write property, so you can modify a control’s font
at runtime using any of the font creation techniques discussed in this
chapter.
Programmers
familiar with the desktop .NET Framework might notice that .NET Compact
Framework controls do not support the concept of ambient properties. On
the desktop, controls use the ambient properties from the parent
control if that property is not specified for the control itself. The
following properties of controls in the desktop .NET Framework are
ambient properties: BackColor, Cursor, Font, and ForeColor.
The
built-in .NET Compact Framework controls do not support ambient
properties. This means that, for example, if you want to select a new
font for a group of controls, you cannot simply change the selected
font in the parent for the group of controls. Instead, you must change
the font for each and every individual control.
|
2. Enumerating Fonts
You can create a font by name, just by specifying the name in a Font constructor. Get a list of available fonts by enumerating the members of the InstalledFontCollection object. We illustrate font enumeration in our FontPicker sample.
3. A Sample Program: FontPicker
Figure 2 shows the FontPicker
sample program. This program lets you select a font by specifying a
face name, a desired size, and (by means of a menu selection) a font
style. A TextBox control displays text using the resulting font.
Listing 1, taken from the FontPicker sample, shows how to create a font and attach it to a text box control.
Listing 1. Font Creation Code from FontPicker Sample
{ int iFont = cboxFont.SelectedIndex; int iSize = cboxSize.SelectedIndex; if (iFont != -1 && iSize != -1) { string strFont = (string)cboxFont.Items[iFont]; string strSize = (string)cboxSize.Items[iSize]; iSize = int.Parse(strSize);
FontStyle fs; if (m_FontStyle == "Regular") fs = FontStyle.Regular; else if (m_FontStyle == "Bold") fs = FontStyle.Bold; else if (m_FontStyle == "Italic") fs = FontStyle.Italic; else if (m_FontStyle == "Strikeout") fs = FontStyle.Strikeout; else fs = FontStyle.Underline;
// Create a new font. Font font = new Font(strFont, (float)iSize, fs);
// Connect font to textbox textSample.Font = font; } }
|
4. A Sample Program: RotateText
The RotateText sample draws rotated text by creating rotated fonts. This program has several output styles, as illustrated in Figures 3 and 4. Figure 3 shows a single line of text rotated at 45 degrees. Figure 4 shows a fan blade—a series of rotated text drawings that spread out from the same drawing point.
Font
rotation is made possible using TrueType fonts, which are currently the
standard for all Windows Mobile devices including standard (Smartphone)
and professional (Pocket PC) editions.
Listing 3 shows a fragment taken from the RotateText program, including the Paint event handler and other core pieces used to draw the rotated text.
Listing 3. Fragment from RotateText with the Elements to Support Rotated Text
public partial class formMain : Form { float m_xDraw; float m_yDraw; int m_degTextRotate; bool m_bDrawFanBlade;
public formMain() { InitializeComponent();
// Calculate center of client area. m_xDraw = (float)ClientRectangle.Right / 2; m_yDraw = (float)(2*ClientRectangle.Bottom / 3);
// Initialize degree of rotation. m_degTextRotate = 0;
// Initialize drawing flag. m_bDrawFanBlade = false; }
private void mitemExit_Click(object sender, EventArgs e) { Close(); }
private Font CreateRotatedFont(string strFaceName, int PointSize, int degRotation, float pixResolution) { // Convert point size to pixel height. float flHeight = ((float)PointSize * pixResolution) / 72.0F; int pixHeight = (int)(flHeight + 0.5);
// Set height negative for "Em-Height" (versus // "character-cell height" for positive size) pixHeight = pixHeight * (-1);
// Fill in LOGFONT structure. var lf = new LogFont(); lf.CharSet = LogFontCharSet.Default; lf.ClipPrecision = LogFontClipPrecision.Default; lf.Escapement = 10 * degRotation; lf.FaceName = ""; lf.Height = pixHeight; lf.Italic = 0; lf.Orientation = 0; lf.OutPrecision = LogFontPrecision.Default; lf.PitchAndFamily = LogFontPitchAndFamily.Default; lf.Quality = LogFontQuality.Default; lf.StrikeOut = 0; lf.Underline = 0; lf.Weight = LogFontWeight.Normal; lf.Width = 0;
return Font.FromLogFont(lf); }
private void formMain_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics;
// Create black brush. Brush brBlack = new SolidBrush(Color.Black);
// Create StringFormat for text drawing details. var sf = new StringFormat(); sf.FormatFlags = StringFormatFlags.NoClip;
if (!m_bDrawFanBlade) // Normal drawing. { // Create font for drawing. Font font = CreateRotatedFont("", 18, m_degTextRotate, g.DpiY);
g.DrawString(this.Text, font, brBlack, m_xDraw, m_yDraw, sf); } else { int cIncrement; cIncrement = (m_degTextRotate == 0) ? 20 : m_degTextRotate; for (int i = 0; i < 360; i += cIncrement) { // Create font for drawing. Font font = CreateRotatedFont("", 18, i, g.DpiY);
g.DrawString(this.Text, font, brBlack, m_xDraw, m_yDraw, sf); } } }
private void textAngle_TextChanged(object sender, EventArgs e) { int angle; try { angle = int.Parse(textAngle.Text); } catch { MessageBox.Show("Integers Only", "RotateText"); textAngle.Text = m_degTextRotate.ToString(); return; } m_degTextRotate = angle; }
private void mitemRedraw_Click(object sender, EventArgs e) { Invalidate(); }
private void mitemFanBlade_Click(object sender, EventArgs e) {
// Set drawing flag. m_bDrawFanBlade = true;
// Force redraw. Invalidate(); Update();
// Reset drawing flag. m_bDrawFanBlade = false; }
private void mitemAnimate_Click(object sender, EventArgs e) { // Store current value. int degTextRotateTemp = m_degTextRotate;
// Use degrees as rotational increment. int cIncrement; cIncrement = (m_degTextRotate == 0) ? 20 : m_degTextRotate;
for (int i = 0; i < 360; i += cIncrement) { m_degTextRotate = i; Invalidate(); Update(); }
// Reset current value. m_degTextRotate = degTextRotateTemp; Invalidate(); Update(); }
} // Class
|