Fundamentals of Brushes

Introduction

After drawing a shape, probably the next step is to fill it out, which is equivalent to painting the interior of a shape. You have many options. At a minimum, you can fill a shape with a color. Even then, you have many options.

Practical LearningPractical Learning: Introducing Brushes

  1. Start Microsoft Visual Studio
  2. Create a new Windows Forms App named WeeklySales1
  3. In the Properties window, right-click Form1.cs and click Rename
  4. Type Exercise (to get Exercise.cs) and press Enter twice

Filling a Rectangle

A rectangle is one of the most fundamental closed geometric shapes. We already know how to draw a rectangle. After drawing a rectangle, you can fill it with a color. To support this, the Graphics class is equipped with an overloaded method named FillRectangle. One of the versions of this method uses the following syntax:

public void FillRectangle(System.Drawing.Brush brush, int x, int y, int width, int height);

As we will see, there are other Graphics methods used to fill out a shape. The first argument of all those methods is a System.Drawing.Brush object. In the above syntax, the x and the y arguments represent the coordinate of the top-left point of the rectangle. The width argument is the distance from the left to the right sides of the rectangle. The height argument is the distance from the top to the bottom sides of the rectangle. As a result, the above method could be callled as follows:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.FillRectangle(some-brush, 20, 20, 200, 160);
}

Introduction to Solid Brushes

A Simple Brush

While a pen is an object used to create a line or the borders of a shape, a brush is an object used to fill out the interior of a closed shape such as a rectangle. There are various types of brushes you can use. The simplest type of brush is referred to as solid. To support solid brushes, the .NET Framework provides a class named SolidBrush. The SolidBrush class is derived from the abstract Brush:

public sealed class SolidBrush : System.Drawing.Brush

The SolidBrush class is defined in the System.Drawing namespace. In reality, to create a solid brush, you have many options.

A Brush as a Color

To let create a simple brush whose only information is a color, the .NET Framework provides a sealed class named Brushes:

public static class Brushes

This class contains only read-only properties. Each property is of type System.Drawing.Brush. The name of each property is the name of a color. Here are examples of those properties:

public static System.Drawing.Brush Green  { get; }
public static System.Drawing.Brush Orange { get; }
public static System.Drawing.Brush Red    { get; }
public static System.Drawing.Brush Blue   { get; }
public static System.Drawing.Brush Black  { get; }

To use one these properties as as a brush, you can declare a Brush variable, accest a known name of a color and qualify it on the Brushes class, and assign that property to your Brush variable. You can then pass that variable as the first argument of the FillRectangle() method. Here are examples:

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

        private void Exercise_Paint(object sender, PaintEventArgs e)
        {
            Brush colorizer = Brushes.Blue;
            e.Graphics.FillRectangle(colorizer, 20, 20, 568, 262);
        }
    }
}

This would produce:

Brush

Instead of first declaring a Brush variable to simply hold a color, since you will hardly do anything with that brush, you can directly pass the Brushes property to a FillRectangle() method. Here are examples:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    BackColor = Color.Salmon;

    e.Graphics.FillRectangle(Brushes.MediumSpringGreen,  20,  20, 282, 82);

    e.Graphics.FillRectangle(Brushes.Linen,             320,  20, 282, 82);

    e.Graphics.FillRectangle(Brushes.PowderBlue,         20, 120, 282, 82);

    e.Graphics.FillRectangle(Brushes.Thistle,           320, 120, 282, 82);

    e.Graphics.FillRectangle(Brushes.LightSeaGreen,      20, 220, 282, 82);

    e.Graphics.FillRectangle(Brushes.DarkViolet,        320, 220, 282, 82);
}

This would produce:

Brush

The System Brushes

If you are developping your application to be used in Microsoft Windows computer, you may be interested in the colors those operating systems use. To help you get those colors, the .NET Framework provides a static class named SystemBrushes:

public static class SystemBrushes

The SystemBrushes class mostly contains only properties (it also contains one method). Every property of the SystemBrushes class is of type System.Drawing.Brush. Every one of those properties is the name a color used in Microsoft Windows. The example of a property is:

public static System.Drawing.Brush Control { get; }

Therefore, to access a Microsoft Windows color, type SystemBrushes. followed by the name of the property/color you want.

Details on Using a Solid Brush

The Color of a Brush

The primary role of a brush is to hold a color so it can use it to paint an object. To help you create a brush and specify its color, the SolidBrush class is equipped with one constructor that uses the following syntax:

public SolidBrush(Color color);

As you can see, the constructor of the SolidBrush class takes a color as argument. The color pargument must be a valid definition of a Color object. As a result, you can access a property/color from the Color structure. Here is an example:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    SolidBrush colorizer = new SolidBrush(Color.Blue);

    e.Graphics.FillRectangle(colorizer, 20, 20, 582, 268);
}

After creating a brush, at any time, you may want to change its color. To allow you to do this, the SolidBrush class is equipped with a property named Color:

public System.Drawing.Color Color { get; set; }

As you can see, SolidBrush.Color is a read-write property. As a result, one way you can use it is to apply a color, or to change the color, of a brush. To do this, type the name of your SolidBrush variable, a period, and the desired name of the color. Here are examples:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    BackColor = Color.Goldenrod;

    SolidBrush colorizer = new SolidBrush(Color.DeepPink);

    e.Graphics.FillRectangle(colorizer, 20, 20, 282, 82);

    colorizer.Color = Color.DimGray;
    e.Graphics.FillRectangle(colorizer, 320,  20, 282, 82);

    colorizer.Color = Color.Aqua;
    e.Graphics.FillRectangle(colorizer,  20, 120, 282, 82);

    colorizer.Color = Color.PeachPuff;
    e.Graphics.FillRectangle(colorizer, 320, 120, 282, 82);

    colorizer.Color = Color.LightSlateGray;
    e.Graphics.FillRectangle(colorizer,  20, 220, 282, 82);

    colorizer.Color = Color.Peru;
    e.Graphics.FillRectangle(colorizer, 320, 220, 282, 82);
}

Disposing of a Brush

Like most objects used in graphics programming, a brush consumes some computer resources. Therefore, after using it, you can free the resources it was using. To assist you with this, the Brush class implements the IDisposable interface. As a result, the Brush class is equipped with an overloaded Dispose() method. The simplest version uses the following syntax:

public void Dispose();

After usign a Brush-based object, you can simply call this method on the brush. Here is an example:

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

    Pen pnBorder = new Pen(Color.GhostWhite, 2.227F);
    SolidBrush colorizer = new SolidBrush(Color.DeepPink);

    grapher.FillRectangle(colorizer, 20, 20, 282, 82);

    colorizer.Color = Color.DimGray;
    grapher.FillRectangle(colorizer, 320, 20, 282, 82);

    colorizer.Color = Color.Aqua;
    grapher.FillRectangle(colorizer, 20, 120, 282, 82);

    colorizer.Color = Color.PeachPuff;
    grapher.FillRectangle(colorizer, 320, 120, 282, 82);

    colorizer.Color = Color.LightSlateGray;
    grapher.FillRectangle(colorizer, 20, 220, 282, 82);

    colorizer.Color = Color.Peru;
    grapher.FillRectangle(colorizer, 320, 220, 282, 82);

    colorizer.Dispose();
}

This would produce:

Brushes - Dispose

Since the Brush class implements the IDisposable interface, instead of calling its Dispose() method, you can use the using() operator to indicate to the compiler that you have an object that is using some resources and those resources need to be freed when the brush stops doing its job.

Practical LearningPractical Learning: Using a Solid Brush

  1. Design the form as follows:

    Company Weekly Sales

    Control Name Text Other Properties
    Label Label   Monday  
    Label Label   Tuesday  
    Label Label   Wednesday  
    Label Label   Thursday  
    Label Label   Friday  
    TextBox TextBox txtMonday   TextAlign: Right
    TextBox TextBox txtTuesday   TextAlign: Right
    TextBox TextBox txtWednesday   TextAlign: Right
    TextBox TextBox txtThursday   TextAlign: Right
    TextBox TextBox txtFriday   TextAlign: Right
    Button Button Generate btnGenerate  
  2. Double-click the Generate button
  3. Change the document as follows:
    namespace WeeklySales2
    {
        public partial class Exercise : Form
        {
            public Exercise()
            {
                InitializeComponent();
            }
                        
            private void btnGenerate_Click(object sender, EventArgs e)
            {
                int monday = 0;
                int tuesday = 0;
                int wednesday = 0;
                int thursday = 0;
                int friday = 0;
                        
                try
                {
                    monday = int.Parse(txtMonday.Text) / 100;
                }
                catch (FormatException)
                {
                    MessageBox.Show("Invalid value");
                }
                        
                try
                {
                    tuesday = int.Parse(txtTuesday.Text) / 100;
                }
                catch (FormatException)
                {
                    MessageBox.Show("Invalid value");
                }
                        
                try
                {
                    wednesday = int.Parse(txtWednesday.Text) / 100;
                }
                catch (FormatException)
                {
                    MessageBox.Show("Invalid value");
                }
                    
                try
                {
                    thursday = int.Parse(txtThursday.Text) / 100;
                }
                catch (FormatException)
                {
                    MessageBox.Show("Invalid value");
                }
                        
                try
                {
                    friday = int.Parse(txtFriday.Text) / 100;
                }
                catch (FormatException)
                {
                    MessageBox.Show("Invalid value");
                }
                    
                CreateGraphics().Clear(BackColor);
                        
                int bottomLine = 400;
                        
                CreateGraphics().FillRectangle(new SolidBrush(Color.Red),    txtMonday.Left    + 35, bottomLine - monday,    40, monday   );
                CreateGraphics().DrawRectangle(new Pen(Color.Black),         txtMonday.Left    + 35, bottomLine - monday,    40, monday   );
                CreateGraphics().FillRectangle(new SolidBrush(Color.Blue),   txtTuesday.Left   + 25, bottomLine - tuesday,   40, tuesday  );
                CreateGraphics().DrawRectangle(new Pen(Color.Black),         txtTuesday.Left   + 25, bottomLine - tuesday,   40, tuesday  );
                CreateGraphics().FillRectangle(new SolidBrush(Color.Green),  txtWednesday.Left + 25, bottomLine - wednesday, 40, wednesday);
                CreateGraphics().DrawRectangle(new Pen(Color.Black),         txtWednesday.Left + 25, bottomLine - wednesday, 40, wednesday);
                CreateGraphics().FillRectangle(new SolidBrush(Color.Maroon), txtThursday.Left  + 25, bottomLine - thursday,  40, thursday );
                CreateGraphics().DrawRectangle(new Pen(Color.Black),         txtThursday.Left  + 25, bottomLine - thursday,  40, thursday );
                CreateGraphics().FillRectangle(new SolidBrush(Color.Orange), txtFriday.Left    + 25, bottomLine - friday,    40, friday   );
                CreateGraphics().DrawRectangle(new Pen(Color.Black),         txtFriday.Left    + 25, bottomLine - friday,    40, friday   );
                        
                CreateGraphics().DrawLine(new Pen(Color.Black, 5.00F), 30, bottomLine, Width - 60, bottomLine);
            }
        }
    }
  4. To execute the application and test it, on the main menu, click Debug and click Start Without Debugging:

    Weekly Sales

  5. Enter some values as follows:
    Monday:    12000
    Tuesday:   11000
    Wednesday: 8500
    Thursday:  16800
    Friday:    17500
  6. Click the Generate button:

    Weekly Sales

  7. After using it, Close the form and return to your programming environemt

A Brush for a Pen

In previous lessons, we saw how to create a pen and specifying its color. As another way to pass a color to a pen, the Pen class is equipped with a constructor whose syntax is:

public Pen(System.Drawing.Brush brush);

As you can see, this constructor takes a brush as argument. That argument would provide the color that the brush need. Here is an example:

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    BackColor = Color.DarkSlateGray;

    Point[] pts = { new( 42,  462),
                    new(272,  62),
                    new(524, 462) };

    using(Brush painter = new SolidBrush(Color.MediumVioletRed))
    {
        Pen penCurrent = new Pen(painter, 26.426F);
        
        e.Graphics.DrawPolygon(penCurrent, pts);
    }
}

This would produce:

Solid Brushes

In the above example, we first defined a Brush object even though we were only interested in its color. As a result, you can access a Brushes object directly for the first argument of a Pen constructor and provide a color there. Here is an example:

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

    BackColor        = Color.DarkSlateGray;

    Pen pnRound      = new(Brushes.SandyBrown, 5.225f);

    float startAngle = 270;
    float sweepAngle = 180;

    Rectangle rect   = new Rectangle(25, 33, 222, 150);
    e.Graphics.DrawArc(pen: pnRound, rect, startAngle, sweepAngle);

    Pen pnCharacter  = new(Brushes.Yellow, 5.225F);

    e.Graphics.DrawLine(pnCharacter, new(45, 33), new(140, 33));

    pnCharacter     = new(Brushes.MistyRose, 8.458F);

    // Updating a pen with a new color from a brush
    pnRound         = new(Brushes.Salmon, 8.458F);
    rect            = new Rectangle(73, 183, 212, 168);
    e.Graphics.DrawArc(pen: pnRound, rect, startAngle, sweepAngle);

    e.Graphics.DrawLine(pnCharacter, new(52, 182), new(200, 182));

    pnCharacter     = new(Brushes.Wheat, 10.449F);

    e.Graphics.DrawLine(pnCharacter, new(45, 350), new(180, 350));

    pnCharacter     = new(Brushes.MediumSpringGreen, 15.525f);

    Point ptStart   = new Point(50, 30);
    Point pnEnd     = new Point(50, 355);

    e.Graphics.DrawLine(pnCharacter, ptStart, pnEnd);
}

This would produce:

Solid Brushes

As you should know already, when creating a pen, you can provide a width for it. If you want to specify the color of the pen using a brush and you want to provide a width with a decimal value, to assist you with this, the Pen class is equipped with a version whose syntax is:

public Pen(System.Drawing.Brush brush, float width);

Adding Borders to a Shape

When drawing a shape for which you want to paint the interior, one way to make it fancy is to draw a border around the shape. This can easily be done by calling a Graphics.Draw...() method that uses the same values as the filling method. This can be done as follows:

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

    Pen pnBorder = new Pen(Color.GhostWhite, 2.227F);
    SolidBrush colorizer = new SolidBrush(Color.DeepPink);

    grapher.FillRectangle(colorizer, 20, 20, 282, 82);
    grapher.DrawRectangle(pnBorder, 20, 20, 282, 82);

    colorizer.Color = Color.DimGray;
    grapher.FillRectangle(colorizer, 320, 20, 282, 82);
    grapher.DrawRectangle(pnBorder, 320, 20, 282, 82);

    colorizer.Color = Color.Aqua;
    grapher.FillRectangle(colorizer, 20, 120, 282, 82);
    grapher.DrawRectangle(pnBorder, 20, 120, 282, 82);

    colorizer.Color = Color.PeachPuff;
    grapher.FillRectangle(colorizer, 320, 120, 282, 82);
    grapher.DrawRectangle(pnBorder, 320, 120, 282, 82);

    colorizer.Color = Color.LightSlateGray;
    grapher.FillRectangle(colorizer, 20, 220, 282, 82);
    grapher.DrawRectangle(pnBorder, 20, 220, 282, 82);

    colorizer.Color = Color.Peru;
    grapher.FillRectangle(colorizer, 320, 220, 282, 82);
    grapher.DrawRectangle(pnBorder, 320, 220, 282, 82);

    colorizer.Dispose();
}

This would produce:

Solid Brushes

A Brush as an Object

Introduction

As you may know already, the .NET Framework provides the Brush class as a generic (abstract) type for brushes, and we saw how to declare a brush variable. In the same way, yo can declare a Brush variable in the body of a class. Here is an example:

public record Painter
{
    Brush brush;
}

We also saw that, since Brush is an abstract class, if you use it to declare a variable, you must initiaze it with a class that derives from Brush, such as SolidBrush.Bitmap class. Here is an example:

public record Painter
{
    Brush brs;

    public Painter()
    {
        brs = new SolidBrush(Color.Black);
    }
}

Producing a Brush

If you have a function or method that creates or manipulates a brush, if you want another procedure to use that brush, you can make the function or method return that brush. You can then call that function or method in another part of your program and get the brush it returns, and then ignore or use that brush. Here are examples of two simple functions that produce brushes:

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

        Brush Create()
        {
            Pen pn = new(Color.Azure, 1.005F);

            Color clr = pn.Color;

            Brush br = new SolidBrush(clr);

            return br;
        }

        SolidBrush Solidify()
        {
            return new SolidBrush(Color.MediumTurquoise);
        }

        private void Draw(Graphics graph)
        {
            Brush brush = Create();
            Pen pnColor = new(brush, 6.725f);
            float startAngle = 270.00F;
            float sweepAngle = 185.85F;

            Rectangle rect = new Rectangle(24, 35, 350, 315);

            Point[] pts = [ new(200, 35), new(100, 35), new(100, 350), new(200, 350) ];
            graph.DrawLines(new(Solidify(), 6.725f), pts);
            graph.DrawArc(pen: pnColor, rect, startAngle, sweepAngle);
        }

        private void pbxCanvas_Paint(object sender, PaintEventArgs e)
        {
            pbxCanvas.BackColor = Color.LightSlateGray;
            
            Draw(e.Graphics);
        }
    }
}

This would produce:

Solid Brushes

A Brush Argument

You can create a function or method that takes a brush as argument. In the body of the function or method, you can ignore or use the brush argument. Here is an example:

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

        private void Draw(Graphics graph, Brush brush)
        {
            Pen pnLiner = new(brush, 6.725f);

            float startAngle = 65.00F;
            float sweepAngle = 225.85F;

            Rectangle rect = new Rectangle(20, 20, 325, 405);
            graph.DrawArc(pen: pnLiner, rect, startAngle, sweepAngle);
        }

        private void pbxCanvas_Paint(object sender, PaintEventArgs e)
        {
            Brush br = new SolidBrush(Color.Firebrick);
            Draw(e.Graphics, br);
        }
    }
}

This would produce:

Solid Brushes

A Brush Property

In a class, you can create a property that is a brush. If you want, you can create a complete property, in which case you would start with a private field of type Brush and then create a property of the same type with a get and a set clauses. Such a property can be created and used as follows:

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

        private void pbxCanvas_Paint(object sender, PaintEventArgs e)
        {
            pbxCanvas.BackColor = Color.DimGray;
            
            Brush colorizer = Brushes.LightYellow;
            Rectangle rect = new(20, 20, 262, 426);

            Painter paint = new Painter(colorizer, rect);

            paint.Fill(e.Graphics);
        }
    }

    public record Painter
    {
        Brush brs;

        public Painter(Brush brush, Rectangle rect)
        {
            (brs, Rectangle) = (brush, rect);
        }

        public Rectangle Rectangle { get; set; }

        public Brush Applier
        {
            get
            {
                return brs;
            }
            set
            {
                brs = value;
            }
        }

        public void Fill(Graphics graph)
        {
            graph.FillRectangle(brs, Rectangle);
        }
    }
}

This would produce:

Solid Brushes

If you want a simple property, you can create it as an automatic one.

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2010-2024, FunctionX Monday 20 May 2024, 12:25 Next