Rotating Text with GDI and Visual Basic

Introduction

Hello. Today, I will show you how to draw words, more specifically fonts, at an angle. This angle can be any angle we supply.

First, the Basics

I would advise you to first read through this article explaining what fonts are, and what type of fonts you get.

Just a small note, before we start the project: Seeing the fact that you will be dealing with a Font object mostly, I have decided to include some other Font functionalities and properties as well. Otherwise, this article would have been very short…

Our Project

The project you will create today will not only allow you to draw text at an angle (in any direction), but it will also allow you to set various Font properties, such as:

  • Bold
  • Underline
  • Colour
  • Size
  • Face
  • Strikethrough
  • Italic

Create a new Visual Basic Windows Forms project and design your form to resemble Figure 1:

Text1
Figure 1: Our design

Let’s code!

The Code

As usual, let me start with the objects that will be used throughout this application. These variables are as follows:

Private FontName As String   'Font Family Name
Private FontSize As String   'Font Size
Private FontColor As Color   'Font Colour
Private FontRegular As Boolean   'Regular Font
Private FontBold As Boolean   'Bold Font
Private FontItalic As Boolean   'Italic Font
Private FontUnderline As Boolean   'Underlined Font
Private FontStrikeThrough As Boolean   'Strikethrough Font
Private FontReal As Font   'Actual Font Object
Private FontRotate As Integer  'Font Rotate Angle

The comments make it a bit easier to understand, don’t they? Basically, all these objects will be used for the various font settings.

To load a list of fonts, add the next code:

Private Sub Form1_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles Me.Load
   'Load System Fonts Into ComboBox
   Dim fFonts As FontFamily
   For Each fFonts In System.Drawing.FontFamily.Families
      cboFonts.Items.Add(fFonts.Name)
   Next
End Sub

Here, I created a FontFamily object. Then, I loop through each font registered on the system and add its name to the cboFonts combobox. If you were to run your application now, you will see the list of fonts inside the Font combobox.

To be able to select a font from the list, you need to add the following code:

Private Sub cboFonts_SelectedIndexChanged(ByVal sender _
   As System.Object, _
   ByVal e As System.EventArgs) Handles _
   cboFonts.SelectedIndexChanged
   If cboFonts.SelectedIndex > -1 Then
      'Get Selected Font Name
      FontName = _
         cboFonts.GetItemText(cboFonts.SelectedIndex)
   End If
End Sub

This is the classic way of obtaining an item selected from the list. It makes use of the built-in list’s Index. The index number starts at 0, and indicates what item was ultimately selected.

Add the following code to be able to set the Font’s size:

Private Sub cboSize_SelectedIndexChanged(ByVal sender _
   As System.Object, ByVal e As System.EventArgs) Handles _
   cboSize.SelectedIndexChanged
   If cboSize.SelectedIndex > -1 Then
      'Get Selected Font Size
      FontSize = cboSize.GetItemText(cboSize.SelectedItem)
   End If
End Sub

It works with the same principle as the previous combobox. Now we have a font and a size.

Add the following code to set the font object’s color:

Private Sub butColor_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butColor.Click
   clrFont.AllowFullOpen = True   'Show Full Dialog Box
   clrFont.AnyColor = True   'Can Select Any Colour
   clrFont.SolidColorOnly = False   'All Colours
   clrFont.ShowHelp = True   'Show WhatsThis Help
   clrFont.FullOpen = True

   If clrFont.ShowDialog() = _
      System.Windows.Forms.DialogResult.OK Then
      FontColor = clrFont.Color   'Set Font Colour
   End If
End Sub

I set numerous properties for the Color dialogbox and allow for user selection. Now, FontColor contains the chosen color. Let’s move on.

The next couple of procedures simply set a Boolean flag (on and off/selected or not selected) for whichever formatting option was selected. Add them now:

Private Sub chkBold_CheckedChanged(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles chkBold.CheckedChanged
   'If Bold Selected Then FB = True
   If chkBold.Checked Then FontBold = True
End Sub

Private Sub chkItalic_CheckedChanged(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles chkItalic.CheckedChanged
   If chkItalic.Checked Then FontItalic = True
End Sub

Private Sub chkUnderline_CheckedChanged(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles chkUnderline.CheckedChanged
   If chkUnderline.Checked Then FontUnderline = True
End Sub

Private Sub chkStrike_CheckedChanged(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles chkStrike.CheckedChanged
   If chkStrike.Checked Then FontStrikeThrough = True
End Sub

Private Sub chkRegular_CheckedChanged(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles chkRegular.CheckedChanged
   If chkRegular.Checked Then FontRegular = True
End Sub

Add the following code to set the Font object’s rotation when focus has left the rotation textbox:

Private Sub txtRotate_Leave(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles txtRotate.Leave
   'Set Rotation Degree
   If IsNumeric(txtRotate.Text) Then FontRotate = _
      Integer.Parse(txtRotate.Text)
End Sub

I simply determined whether or not the entered text was numeric, then converted the entered value to a numeric value.

Add the FontStuff sub that will put all the pieces of the puzzle together:

Private Sub FontStuff()

   Dim width As Double    'Width Of Font
   Dim height As Double   'Height Of Font

   'Create New Bitmap Object To "Save" Graphic Image
   Dim bmp As New Bitmap(picPreview.Width, _
      picPreview.Height)
   'Create Graphics Object To Draw To
   Dim g As Graphics = Graphics.FromImage(bmp)

   If FontRegular Then   'If Regular Font
      'Create Font Based On Regular Style
      FontReal = New Font(FontName, FontSize, _
         FontStyle.Regular, GraphicsUnit.Point)
      'Determine Text Width Based On Font
      width = g.MeasureString(txtText.Text, FontReal).Width
      'Determine Height Of Text Based On Font
      height = g.MeasureString(txtText.Text, FontReal).Height
   End If

   If FontBold Then
      FontReal = New Font(FontName, FontSize, _
         FontStyle.Bold, GraphicsUnit.Point)
      width = g.MeasureString(txtText.Text, FontReal).Width
      height = g.MeasureString(txtText.Text, FontReal).Height
   End If

   If FontItalic Then
      FontReal = New Font(FontName, FontSize, _
         FontStyle.Italic, GraphicsUnit.Point)
      width = g.MeasureString(txtText.Text, FontReal).Width
      height = g.MeasureString(txtText.Text, FontReal).Height
   End If

   If FontUnderline = True Then
      FontReal = New Font(FontName, FontSize, _
         FontStyle.Underline, GraphicsUnit.Point)
      width = g.MeasureString(txtText.Text, FontReal).Width
      height = g.MeasureString(txtText.Text, FontReal).Height
   End If

   If FontStrikeThrough Then
      FontReal = New Font(FontName, FontSize, _
         FontStyle.Underline, GraphicsUnit.Point)
      width = g.MeasureString(txtText.Text, FontReal).Width
      height = g.MeasureString(txtText.Text, FontReal).Height
   End If

   'Angle For Rotating
   Dim angleRadian As Double = _
      ((FontRotate Mod 360) / 180) * Math.PI
   'Font Color
   Dim b As Brush = New SolidBrush(FontColor)

   'Between 0 To 90 And -270 And -360
   If (FontRotate >= 0 AndAlso FontRotate < 90) Or _
      (FontRotate < -270 AndAlso FontRotate >= -360) Then
      g.TranslateTransform(CInt(Math.Sin(angleRadian) * height), 0)

   'Between 90 To 180 To -180 To -270
   ElseIf (FontRotate >= 90 AndAlso FontRotate < 180) Or _
      (FontRotate < -180 AndAlso FontRotate >= -270) Then
      g.TranslateTransform(ClientRectangle.Width, CInt(height - _
         (Math.Sin(angleRadian) * height)))

   'Between 180 To 270 And -90 To -180
   ElseIf (FontRotate >= 180 AndAlso FontRotate < 270) Or _
      (FontRotate < -90 AndAlso FontRotate >= -180) Then
      g.TranslateTransform(0 + CInt(Math.Sin(angleRadian) * height), _
      ClientRectangle.Height)
   Else
      g.TranslateTransform(0, ClientRectangle.Height - _
         CInt(Math.Cos(angleRadian) * height))
   End If

   g.RotateTransform(CInt(FontRotate))   'Rotate
   'Draw The String / Font
   g.DrawString(txtText.Text, FontReal, b, 0, 0)
   picPreview.Image = bmp   'Display Font "Image"
   '   g.ResetTransform()   'Reset

End Sub

The first parts of this sub mainly concentrate on what settings were set. After it has determined the specific setting, it resizes the font object to fit in not only the text, but the formatting as well. All this happens with the MeasureString property; here is more information on it.

Lastly, this sub determines the rotation value and, based on the rotation value, uses a bit of math to create the desired writing at the desired angle. Here is more information on RotateTransform and DrawString.

Add the call to the FontStuff sub:

Private Sub butApply_Click(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles butApply.Click
   FontStuff()   'Call font Creation Sub

End Sub

When run, your form might look like Figure 2:

Text2
Figure 2: Rotation in action

Conclusion

I hope you have enjoyed this article. Until next time, this is me signing off!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read