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:
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:
Figure 2: Rotation in action
Conclusion
I hope you have enjoyed this article. Until next time, this is me signing off!