Flowing Text from the Font


Circles and squares are okay, but they don't always communicate much, unless you are Joan Miró. Most of us depend on text to say what we mean. Fortunately, GDI+ has features galore that place text on your graphics surface.

Before graphical user interfaces were all the rage, text wasn't really an issue; you either used the characters built into the system, or nothing. On the screen, each letter of the alphabet was designed into the hardware of the computer or monitor, and any particular character could only appear within each square of the predefined 80x24 grid. Printers were a little better, becaue you could backspace and retype over previously typed positions to generate either bold or underscore text. Still, you were generally limited to one font, or just a small handful of basic fonts embedded in the printer's memory.

Such limitations are a thing of the past. All text in Microsoft Windows appears courtesy of fonts, descriptions of character shapes that can be resized or stretched or emphasized to meet any text need. And because the user can add fonts to the system at any time, and from any third-party source, the variety of these fonts is amazing. But you already know all this. Let's get on to the code.

To gain access to a font for use in your graphics, create an instance of the System.Drawing.Font class, passing it at least the font name and point size, and an optional style reference.

Dim basicFont As New Font("Arial", 14, FontStyle.Italic) 


Naturally, the list of available fonts varies by system; if you're going to go beyond the basic preinstalled fonts supplied with Windows, you should confirm that a named font is really available, and have a fallback option if it is not. You can get a list of all fonts by asking GDI+ nicely. All fonts appear in "families," where each named family may have bold, italic, and other variations installed as separate font files. The following code block adds a list of all installed font families to a ListBox control.

Dim allFonts As New Drawing.Text.InstalledFontCollection() For Each oneFamily As Drawing.FontFamily In allFonts.Families    ListBox1.Items.Add(oneFamily.Name) Next oneFamily 


If the font you need isn't available and you aren't sure what to use, let GDI+ choose for you. It includes a few generic fonts for emergency use.

Drawing.FontFamily.GenericMonospace Drawing.FontFamily.GenericSansSerif Drawing.FontFamily.GenericSerif 


Getting back to using fonts in actual drawing: The Graphics object includes a DrawString method that blasts out some text to the canvas.

Private Sub PictureBox1_Paint(ByVal sender As Object, _       ByVal e As System.Windows.Forms.PaintEventArgs) _       Handles PictureBox1.Paint    Dim basicFont As New Font("Arial", 14, FontStyle.Italic)    e.Graphics.DrawString("This is a test", basicFont, _       Brushes.Black, 0, 0)    basicFont.Dispose() End Sub 


Figure 17-4 shows the output for this code block. In most of the sample code in this chapter, I'll be outputting content to a PictureBox control named PictureBox1 that I've placed on the form of a new Windows Forms application. I've also set that control's BorderStyle property to FixedSingle, and its BackColor property to white, so that I can visualize the edges of the canvas. Drawing occurs in the Paint event handler, which gets called whenever the picture box needs to be refreshed, as when another window obscures it and then goes away. In the remaining code examples, I won't be including the "Sub PictureBox1_Paint" method definition, just the code that goes inside of it.

Figure 17-4. This is a test for sure


Of course, you can mix and match fonts on a single output canvas. This code includes text using Arial 14 and Arial 18.

Dim basicFont As New Font("Arial", 14) Dim strongFont As New Font("Arial", 18, FontStyle.Bold) Dim offset As Single = 0.0 Dim showText As String Dim textSize As Drawing.SizeF showText = "This is some " textSize = e.Graphics.MeasureString(showText, basicFont) e.Graphics.DrawString(showText, basicFont, _    Brushes.Black, offset, 0) offset += textSize.Width showText = "strong" textSize = e.Graphics.MeasureString(showText, strongFont) e.Graphics.DrawString(showText, strongFont, _    Brushes.Black, offset, 0) offset += textSize.Width showText = "text." textSize = e.Graphics.MeasureString(showText, basicFont) e.Graphics.DrawString(showText, basicFont, _    Brushes.Black, offset, 0) offset += textSize.Width strongFont.Dispose() basicFont.Dispose() 


The output of this code appears in the top box of Figure 17-5, and it's okay. But I want the bottom edges of the main body parts of each text blockthat is, the baselines of each blockto line up properly, as shown in the lower box of Figure 17-5.

Figure 17-5. The good and the bad; both ugly


Doing all of the fancy font-lining-up stuff is kind of a pain in the neck. You have to do all sorts of measuring based on the original font design as extrapolated onto the pixel-based screen device. Then you connect the knee bone to the thigh bone, and so on. Here's the code I used to generate the second lined-up image.

Dim basicFont As New Font("Arial", 14) Dim strongFont As New Font("Arial", 18, FontStyle.Bold) Dim offset As Single = 0.0 Dim showText As String Dim textSize As Drawing.SizeF Dim basicTop As Single Dim strongTop As Single Dim strongFactor As Single Dim basicFactor As Single ' ----- The Font Family uses design units, probably '       specified by the original designer of the font. '       Map these units to display units (points). strongFactor = strongFont.FontFamily.GetLineSpacing( _    FontStyle.Regular) / strongFont.Height basicFactor = basicFont.FontFamily.GetLineSpacing( _    FontStyle.Regular) / basicFont.Height ' ----- Determine the location of each font's baseline. strongTop = (strongFont.FontFamily.GetLineSpacing( _    FontStyle.Regular) - strongFont.FontFamily.GetCellDescent( _    FontStyle.Regular)) / strongFactor basicTop = (basicFont.FontFamily.GetLineSpacing( _    FontStyle.Regular) - basicFont.FontFamily.GetCellDescent( _    FontStyle.Regular)) / basicFactor ' ----- Draw a line that proves the text lines up. e.Graphics.DrawLine(Pens.Red, 0, strongTop, _    e.ClipRectangle.Width, strongTop) ' ----- Show each part of the text. showText = "This is some " textSize = e.Graphics.MeasureString(showText, basicFont) e.Graphics.DrawString(showText, basicFont, _    Brushes.Black, offset, strongTop - basicTop) offset += textSize.Width showText = "strong" textSize = e.Graphics.MeasureString(showText, strongFont) e.Graphics.DrawString(showText, strongFont, _    Brushes.Black, offset, 0) offset += textSize.Width showText = "text." textSize = e.Graphics.MeasureString(showText, basicFont) e.Graphics.DrawString(showText, basicFont, _    Brushes.Black, offset, strongTop - basicTop) offset += textSize.Width strongFont.Dispose() basicFont.Dispose() 


There's a lot more calculating going on in that code. And I didn't even try to tackle things like kerning, ligatures, or anything else having to do with typography. Anyway, if you need to perform complex font manipulation, GDI+ does expose all of the details so that you can do it properly. If you just want to output line after line of text using the same font, call the font's GetHeight method for each line displayed.

verticalOffset += useFont.GetHeight(e.Graphics) 


Enough of that complex stuff. There are easy and cool things to do with text, too. Did you notice that text output uses brushes and not pens? This means that you can draw text using any brush you can create. This block of code uses the Library Project's "LookupItem" bitmap brush to display some bitmap-based text.

Dim useBrush As Brush = New TextureBrush( _    Image.FromFile("LookupItem.bmp")) Dim useFont As New Font("Arial", 60, FontStyle.Bold) e.Graphics.DrawString("Wow!", useFont, useBrush, 0, 0) useFont.Dispose() useBrush.Dispose() 


The output appears in Figure 17-6.

Figure 17-6. The merger of text and graphics





Start-to-Finish Visual Basic 2005. Learn Visual Basic 2005 as You Design and Develop a Complete Application
Start-to-Finish Visual Basic 2005: Learn Visual Basic 2005 as You Design and Develop a Complete Application
ISBN: 0321398009
EAN: 2147483647
Year: 2006
Pages: 247
Authors: Tim Patrick

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net