Introduction to Fonts

Overview

One of the characteristics of communication is the written word. To write a word, you use letters, symbols, digits, etc. The group of symbols understandable to a particular language is its alphabet. Like everything else, an alphabet has a name; and the name of the alphabet is related to its corresponding language. For example, there is such a thing as the English alphabet, the German alphabet, and so on.

One of the particularities of a regular alphabet is that it must have a specific way to represent its primary basic symbols. In English, the basic symbols are A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, and Z. There are two ways to represent a letter (in many languages): uppercase and lowercase.

Besides the regular letters of an alphabet, when creating or representing the written words, a language can add some signs to some words. This can assist in the pronunciation or the variations, which can subsequently make the language richer. For example, two languages may use similar letters in their alphabets but one of the languages may add some signs such as accents to some of its letters.

The letters used in an alphabet and the digits used to represent numbers might have primarily been created or designed in a standard way. After a while, some variations could have been added in the way some letters drawn or represented. Here are examples:

Notice that the W and the C on each expression is different. With the advent of computers, new demands for better and more sophisticated techniques of representing words were needed.

Practical LearningPractical Learning: Introducing .NET Framework Collections

  1. Start Microsoft Visual Studio
  2. Create a Windows Forms App named DrawingStrings

The Digits

The letters of an alphabet are typically used to create or represent spoken words. To count, to measure, to represent numbers, or to perform calculations, other symbols were created. Examples of such symbols are 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. Because there are 10 of them, they are referred to as digits.

A font is the group of characteristics by which a letter or printed symbol is drawn (or was designed). A font is an abstract (non-physical) object used to draw some symbols on paper, a computer monitor, or another device (PDA, oscillator, etc).

Getting a Font

A font is created by a graphic artist or developed by a corporation. Once the font has been designed, it is created as a computer application and must be installed in the device that will use it. This means that the font must be installed in the computer, the printer, or the device that can then use it. This also means that there are various ways you can get a font to your device. Most computer-related objects (PCs, printers, oscillators, PDAs, etc) come with one or more fonts already installed. You can also acquire or purchase a font and install it on a computer. You can also download a free font from the Internet and install it.

The Fonts of a Device

To see the names of fonts installed in a computer that is running Microsoft Windows, in the Control Panel of MS Windows 7, in C:\Windows (MS Windows 10 and 11), you can double-click the Fonts folder. Here is an example:

Because it is something that must be installed on, and can be removed from, the computer, it is likely that two computers would not have the same (list of) fonts. Still, because an operating system installs some default or popular fonts by default, there are fonts that are likely to be found on every regular installation of a certain operating system such as Microsoft Windows. This implies that, if you create a (commercial) application that you intend to distribute to people (customers) you do not know, you should assume that your audience would not have some or any of the fancy fonts you have in your computer.

You have two alternatives when selecting the fonts used in your application you intend to distribute. If you own the font, you can distribute it with your application. Another, easier, solution, is to use only the most likely fonts to be found on most computers.

Providing a Font

If you are visually working on a Windows control that supports text, after selecting the control from the Toolbox and adding it to a form or another control container, you may want to select the font by which the control's text will be painted. To do this, in the Properties window of the control, click the Font field, then click its ellipsis button. A dialog box would display. In the Font list box, select the desired font and click OK.

In the .NET Framework, the primary piece of information about a font is held by a sealed class named Font:

public sealed class Font : MarshalByRefObject,
                           ICloneable,
                           IDisposable,
                           System.Runtime.Serialization.ISerializable

Fundamentals of Text Drawing

Introduction

Besides the regular geometric and irregular non-geometric shapes we have seen so far, you can draw text on a form or a control. You have many options. The primary way we know about displaying text on a form is by using a Window control. Probably the easiest way is by using a label. To do this, you can visually add a label. If you want text that holds a link, you can use a link label. There are other available controls. You can also dynamically create a control by declaring a variable of its class. Here is an example:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = "Fallacies - The Practice of Faulty Reasoning";
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(40, 50);
            Controls.Add(lblTitle);
        }
    }
}

This would produce:

Draw String

After creating such a control, you can customize the way it displays its text.

Introduction to Drawing a String

The Graphics class provides its own means of drawing text. The class makes it possible through an overloaded method named DrawString. One of the simplest versions uses the following syntax:

public void DrawString(string s, Font font, Brush brush, float x, float y);

The first argument is the string that will be drawn on a graphical object. The second argument is the font that the compiler will use to draw the text held by the first argument. The third argument is a brush. It can be provided as a color. The last two arguments are the (top-left) coordinates where the beginning of the string would be.

Introduction to the Characteristics of a Font

The Name of a Font

The primary piece of information about a font is its name. To let you access the name of a font, the Font class is equipped with a read-only property named Name:

public string Name { get; }

The Size of Text

The size of a font is the width and the height that will be used to draw a character. It is important to know that this size refers to the visual 2-dimensional size and not to the memory size. This means that the letters i, N, g, M, l, and W obviously use different visual space but all of them use the same amount of memory space.

To support the minimum information to create a font, the Font class is equipped with the following constructor:

public Font(string familyName, float emSize);

The first argument is the name of the font you want to use. The second argument is a floating-point number that represents the size you want to apply to the font. Here is an example:

void btnWriteClick(object sender, EventArgs e)
{
  Font fntWrite = new Font("Verdana", 16.0F);
}

Once you have created a font, if you are working on a Windows control, you can assign that variable to the Font property of the control. Here is an example:

private void Exercise_Load(object sender, EventArgs e)
{
    Label lblTitle = new Label();

    Font fntWrite = new Font("Times New Roman", 22.238F);

    lblTitle.Text = "Fallacies - The Practice of Faulty Reasoning";
    lblTitle.AutoSize = true;
    lblTitle.Location = new Point(22, 50);
    lblTitle.Font = fntWrite;
    Controls.Add(lblTitle);
}

This would produce:

Drawing Strings

If you are trying to paint text, after creating a font, you can pass it as the second argument of the Graphics.DrawString() method we saw already. Here is an example:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            Font fntWrite = new Font("Arial Rounded MT", 39.336F);

            lblTitle.Text = "Appeal to authority";
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(22, 20);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Font fntWrite = new Font("Arial Rounded MT", 39.336F);

            Brush brush = new SolidBrush(Color.Black);
            e.Graphics.DrawString("Appeal to authority", fntWrite, brush, 22.00F, 128.824F);
        }
    }
}

This would produce:

Drawing Strings

In the above example, we first declared a Font variable and later used it. If you are not planning to use a font many times, you can omit declaring a variable for it but create it directly where it is needed. Here are examples:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = "Business Plan";
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(12, 20);
            lblTitle.Font = new Font("Calligraph421 BT", 62.137F);
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawString("Business Plan",
                                  new Font("Calligraph421 BT", 62.137F),
                                  Brushes.Black, 12.00F, 208.824F);
        }
    }
}

This would produce:

Drawing Strings

To let you find out the size of an existing font, the Font class is equipped with a (read-only) property named Size:

public float Size { get; }

Other Techniques to Draw a String

Drawing Text from a Point

So far, to draw text, we specified the X and the Y coordinates where the compiler would start drawing. As an alternative, you can provide the coordinates as a point. To support this, the Graphics class provides the following version of its DrawString() method:

public void DrawString(string? s,
                       System.Drawing.Font font,
                       System.Drawing.Brush brush,
                       System.Drawing.PointF point);

When calling this method, provide a point as the last argument. The values of that point can be integers or decimal numbers. Here is an example:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        Point ptOrigin = new Point(22, 20);
        
        private readonly string? strDisplay = "Request for Time Off";
        private readonly Font fntWrite = new Font("Papyrus", 34.424F);

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = strDisplay;
            lblTitle.AutoSize = true;
            lblTitle.Location = ptOrigin;
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics graph = e.Graphics;
            
            ptOrigin.Y = 128;

            Brush brush = new SolidBrush(Color.Black);
            graph.DrawString(strDisplay, fntWrite, brush, ptOrigin);
        }
    }
}

This would produce:

Drawing Strings - Drawing Text from a Point

Drawing an Array of Characters

You may already know that a string is primarily an array of characters. If you have such a list or array of characters, you can use it to draw text. To do this, pass the array or its variable to the Graphics.DrawString() method used above. Here is an example:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        char[] strBiology = { 'B', 'i', 'o', 'l', 'o', 'g', 'y' };
        Font   fntWrite   = new Font("Old English Text MT", 118.573F);

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = new(strBiology);
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(2, 2);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics grapher = e.Graphics;

            Brush brush = new SolidBrush(Color.Black);
            grapher.DrawString(strBiology, fntWrite, brush, 2, 218.824F);
        }
    }
}

This would produce:

Drawing Strings

To support a better way to manage the computer memory that holds the array of characters, the Graphics.DrawString() is available in the following version:

public void DrawString(ReadOnlySpan<char> s,
                       System.Drawing.Font font,
                       System.Drawing.Brush brush,
                       float x,
                       float y);

When calling this method, as you may know from C#, you can first declare an array variable and then pass it to a constructor of the ReadOnlySpan<T> structure. You can then pass the ReadOnlySpan<T> variable to the Graphics.DrawString() method used above. Here is an example:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        Font fntWrite = new Font("Old English Text MT", 22.318F);
        char[] strUppercase = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                              'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
                              'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
        char[] strLowercase = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
                              'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
                              'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            ReadOnlySpan<char> rosString = new ReadOnlySpan<char>(strUppercase);

            lblTitle.Text = new(rosString);
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(12, 35);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics grapher = e.Graphics;

            ReadOnlySpan<char> rosString = new ReadOnlySpan<char>(strLowercase);

            Brush brush = new SolidBrush(Color.Black);
            grapher.DrawString(rosString, fntWrite, brush, 22.00F, 128.824F);
        }
    }
}

This would produce:

Drawing Strings

You may already know that the array variable may be necessary only if you are planning to use that variable many times. Otherwise, you can create the array directly in the parentheses of the ReadOnlySpan<T>() constructor. You can then use the ReadOnlySpan<T> variable as you see fit. This can be done as follows:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        Font fntWrite = new Font("Old English Text MT", 86.318F);

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            ReadOnlySpan<char> rosString = new ReadOnlySpan<char>([ 'B', 'i', 'o', 'l', 'o', 'g', 'y' ]);

            lblTitle.Text = new(rosString);
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(14, 5);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics grapher = e.Graphics;

            ReadOnlySpan<char> rosString = new ReadOnlySpan<char>([ 'B', 'i', 'o', 'l', 'o', 'g', 'y' ]);

            Brush brush = new SolidBrush(Color.Black);
            grapher.DrawString(rosString, fntWrite, brush, 22.00F, 128.824F);
        }
    }
}

In the same way, you don't have to first declare a ReadOnlySpan<T> variable. You can directly pass a ReadOnlySpan<T> object to Graphics.DrawString(() method by calling its ReadOnlySpan<T> constructor. This can be done as follows:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        Font fntWrite = new Font("Old English Text MT", 86.318F);

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = new(new ReadOnlySpan<char>(['B', 'i', 'o', 'l', 'o', 'g', 'y']));
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(14, 5);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics grapher = e.Graphics;

            Brush brush = new SolidBrush(Color.Black);
            grapher.DrawString(new ReadOnlySpan<char>(['B', 'i', 'o', 'l', 'o', 'g', 'y']),
                               fntWrite, brush, 22.00F, 128.824F);
        }
    }
}

In the above example, we provided the starting point of text drawing with an X and Y coordinates. As alternative is to provide the coordinates as a starting point. To support this, the Graphics class provides another version of its DrawString() method. Its syntax is:

public void DrawString(ReadOnlySpan<char> s, 
                       System.Drawing.Font font, 
                       System.Drawing.Brush brush,
                       System.Drawing.PointF point);

Here is an example of calling this method:

using System;
using System.Windows.Forms;

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        Point ptOrigin = new Point(8, 20);
        
        private readonly Font   fntWrite = new Font("Viner Hand ITC", 47.557F);
        private readonly char[] display  = new char[] { 'N', 'a', 't', 'i', 'o', 'n', 'a', 'l', ' ',
                                                        'H', 'o', 'l', 'i', 'd', 'a', 'y', 's' };

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();
            ReadOnlySpan<char> rosDisplay = display;
            
            lblTitle.Text = rosDisplay.ToString();
            lblTitle.AutoSize = true;
            lblTitle.Location = ptOrigin;
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Graphics graph = e.Graphics;
            ReadOnlySpan<char> rosDisplay = display;
            
            ptOrigin.Y = 208;

            Brush brush = new SolidBrush(Color.Black);
            graph.DrawString(rosDisplay, fntWrite, brush, ptOrigin);
        }
    }
}

This would produce:

Drawing Strings - Bold

Drawing a String Within a Rectangle

So far, to draw a string, we simply specified where the compiler should start drawing text. Consider the following two examples:

namespace DrawingStrings
{
    public partial class Exercise : Form
    {
        private readonly string? strDisplay = "Community Services";
        private readonly Font    fntWrite   = new Font("Calisto MT", 42.137F);

        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Label lblTitle = new Label();

            lblTitle.Text = strDisplay;
            lblTitle.AutoSize = true;
            lblTitle.Location = new Point(12, 20);
            lblTitle.Font = fntWrite;
            Controls.Add(lblTitle);
        }

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawString(strDisplay,
                                  fntWrite,
                                  Brushes.Black, 12.00F, 128.824F);
        }
    }
}

This would produce:

Drawing a String Within a Rectangle

So far, we have seen that we can use a Windows control, such as a label, to draw or display a string. A label is a visual Windows control. As a result, it has a size, represented by a width and a height. When it comes to drawing a string, we have seen that the Graphics class provides its own means to draw a string. As it happens, the Windows controls, such as a label, follow some techniques and means to draw text. As it happens, you can also specify a size within which text should be drawn. This is one of the areas where a Windows control and a Graphics object do things differently.

Sometimes, you may want to confine your string to a specific area so that the string must not be drawn outside that area. If you are working with a visual control such as a label, you can check how that control works. For example, for a Windows control, you can specify that you will manually set its size. To this for a label, you can set its AutoSize to False, which indicates that it is not the length of the text that will specify the size, but you would set that size yourself. To support the ability to draw a string in a specified rectangle, the Graphics class porvides a version of its DrawString() method whose syntax is:

public void DrawString(string? s,
                       System.Drawing.Font font,
                       System.Drawing.Brush brush,
                       System.Drawing.RectangleF layoutRectangle);

When calling this version of the Graphics.DrawString() method, pass a rectangle as the last argument. This can be done as follows:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    Graphics graph = e.Graphics;
    string? strDisplay = "Community Development";
    Font fntWrite = new Font("Calisto MT", 45.369F);
    Rectangle rect = new Rectangle(12, 12, 360, 185);

    graph.DrawString(strDisplay,
                     fntWrite,
                     Brushes.Black, rect);

    graph.DrawRectangle(new Pen(Color.Blue, 2.325F), rect);
}

This would produce:

Drawing a String Within a Rectangle

As you can see, you may provide a rectangle that too small for the string you are trying to display. Therefore, when providing your rectangle, make sure it is larger than, or large enough for, the text you want to draw. Here is an example:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    Graphics graph = e.Graphics;
    string? strDisplay = "Community Development";
    Font fntWrite = new Font("Calisto MT", 45.369F);
    Rectangle rect = new Rectangle(12, 12, 575, 225);

    graph.DrawString(strDisplay,
                     fntWrite,
                     Brushes.Black, rect);

    graph.DrawRectangle(new Pen(Color.Blue, 1.525F), rect);
}

This would produce:

Drawing a String Within a Rectangle

In the above example, we provided a string for the text to draw. As an alternative, you may have a series of characters to draw. Instead of simply using a string, the Graphics class allows you to use a list of symbols with better memory management. This can be done with the following version of the Graphics.DrawString() method:

public void DrawString(ReadOnlySpan<char> s,
                       System.Drawing.Font font,
                       System.Drawing.Brush brush,
                       System.Drawing.RectangleF layoutRectangle);

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2010-2024, FunctionX Monday 03 June 2024, 15:36 Next