The following code draws the text when the form repaints. It starts by creating a big font.
Next the code gets some information about the font's dimensions. See my book Visual Basic 2005 Programmer's Reference for a detailed discussion but briefly these values are:
- internal_leading
- Space above the characters that is still considered part of the character's height
- em_height
- The height of the characters from below the internal_leading to the bottom of the descenders (for example, where g and j descend below the baseline)
- ascent
- The height of the characters from the baseline to the top of the drawing area including the internal leading
- descent
- The distance the characters may extend below the baseline
- cell_height
- The total height of the text from bottom to top including the internal leading and descent
- line_spacing
- The distance between the top of one line of text and the top of the next line of text
- external_leading
- The distance between the bottom of one line of text (including descent) and the top of the next line of text (including internal leading)
After calculating the font metrics, the code determines where the actual text will be drawn. The text in this example doesn't use descenders so the text goes from below the internal leading to the baseline. However real fonts often leave extra space below the internal leading, drop below the baseline, and otherwise violate their metrics slightly. The ways this happens depends on the particular font and its characteristics (bold, italic, and so forth). This example fudges the drawing area down a bit to get a better fit to the actual text.
The code makes a linear gradient brush to fill the text area. It shades the colors red, orange, yellow, green, blue, and indigo (violet looked too pale) over this area. The code maps red and indigo to two positions at the ends of the region so the top of the characters is a bit extra red and the bottom is a tad extra indigo.
Finally, the code draws the text using the rainbow brush. Extra debugging code draws the text's drawing area, internal leading line, baseline, and descent line.
|
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As _
System.Windows.Forms.PaintEventArgs) Handles _
MyBase.Paint
Const TXT As String = "RAINBOW!"
Dim the_font As New Font("Times New Roman", 150, _
FontStyle.Bold, GraphicsUnit.Pixel)
' Get font metrics.
' (See my book "Visual Basic 2005 Programmer's
' Reference"
' page 609 for more information on font metrics.
' See http://www.vb-helper.com/vb_prog_ref.htm
' for more about the book.)
Dim em_height As Integer = _
the_font.FontFamily.GetEmHeight(FontStyle.Bold)
Dim em_height_pix As Single = the_font.Size
Dim design_to_pixels As Single = the_font.Size / _
em_height
Dim ascent As Integer = _
the_font.FontFamily.GetCellAscent(FontStyle.Bold)
Dim ascent_pix As Single = ascent * design_to_pixels
Dim descent As Integer = _
the_font.FontFamily.GetCellDescent(FontStyle.Bold)
Dim descent_pix As Single = descent * design_to_pixels
Dim cell_height_pix As Single = ascent_pix + descent_pix
Dim internal_leading_pix As Single = cell_height_pix - _
em_height_pix
Dim line_spacing As Integer = _
the_font.FontFamily.GetLineSpacing(FontStyle.Bold)
Dim line_spacing_pix As Single = line_spacing * _
design_to_pixels
Dim external_leading_pix As Single = line_spacing_pix - _
cell_height_pix
' See how big the text is.
Dim text_size As SizeF = e.Graphics.MeasureString(TXT, _
the_font)
Dim x0 As Integer = CInt((Me.ClientSize.Width - _
text_size.Width) / 2)
Dim y0 As Integer = CInt((Me.ClientSize.Height - _
text_size.Height) / 2)
' Get the Y coordinates that the brush should span.
Dim brush_y0 As Integer = CInt(y0 + _
internal_leading_pix)
Dim brush_y1 As Integer = CInt(y0 + ascent_pix)
' Fudge the brush down a smidgen.
brush_y0 += CInt(internal_leading_pix)
brush_y1 += 5
' Make a brush to color the area.
Dim the_brush As New LinearGradientBrush( _
New Point(x0, brush_y0), _
New Point(x0, brush_y1), _
Color.Red, Color.Violet)
Dim color_blend As New ColorBlend
color_blend.Colors = New Color() {Color.Red, Color.Red, _
Color.Orange, Color.Yellow, Color.Green, _
Color.Blue, Color.Indigo, Color.Indigo}
color_blend.Positions = New Single() {0, 1 / 7, 2 / 7, _
3 / 7, 4 / 7, 5 / 7, 6 / 7, 1}
the_brush.InterpolationColors = color_blend
' Draw the text.
e.Graphics.DrawString(TXT, the_font, the_brush, x0, y0)
#If False Then
' Debugging statements.
' Fill a rainbow rectangle for reference.
e.Graphics.FillRectangle(the_brush, x0, brush_y0, 10, _
brush_y1 - brush_y0)
' Outline the text area.
e.Graphics.DrawRectangle(Pens.Blue, x0, y0, _
text_size.Width, text_size.Height)
' Draw the internal leading line.
Dim y As Single
y = y0 + internal_leading_pix
e.Graphics.DrawLine(Pens.Red, x0, y, x0 + _
text_size.Width, y)
' Draw the internal baseline.
y = y0 + ascent_pix
e.Graphics.DrawLine(Pens.Red, x0, y, x0 + _
text_size.Width, y)
' Draw the internal descent line.
y = y0 + cell_height_pix
e.Graphics.DrawLine(Pens.Red, x0, y, x0 + _
text_size.Width, y)
#End If
the_brush.Dispose()
the_font.Dispose()
End Sub
|