Reader Level:
ARTICLE

How Pen and Brush Work in GDI+

Posted by Sivaraman Dhamodaran Articles | Articles C# August 19, 2013
This article hepls you to understand the importance of Pen and Brush objects in GDI+
  • 1
  • 0
  • 3481
Download Files:
 

1. Introduction

 

In this article we will have a look at how to draw using the GDI+ functions available with .Net. GDI stands for Graphical Device Interface and using that you can create rich drawing applications and show useful information on the form as a drawing, say for example showing a pie chart of sales for the past 5 years.

 

In this article I will show how to draw using Pens and Brushes.

 

2. What is Pen and Brush?

 

A Pen is a graphics object that can be used to draw lines. A pen has the properties like the color of the Pen and thickness of the Pen. A Brush is also a graphics object that can be used to paint the region. Suppose you want to fill the area, you can use a Brush. Think about painting a door, a wooden plate and so on.

 

In this article I will show how to use the Plain Solid Brush, Gradient Brush and Hatch Brush.

 

3. About the Finished Example

 

The following is a screenshot of the finished application:

 

Pic01.jpg


The Black screen is the Panel control used in this example as a drawing canvas. When the Fill Brush is not enabled, whatever you draw is drawn using only the Pen. That means you see the drawing outline that is Rectangle outline in our example. You can switch between Solid Brush and Advanced brush using the Advanced Brush checkbox. When the checkbox is enabled, you see the advanced brush options that can be toggled between Hatch and Gradient using the Toggle switch shown as seven in the screen shot above.

 

4. Drawing the Rectangle Object

 

To draw a rectangle in GDI+ we need its size and position. So in the first part of the development, we placed the controls to collect the Rectangle's position and the size (Section 1 and 2 in the screenshot above). Then the rectangle is drawn in the Panel named as DrawingCanvas.

 

1. First the required namespace to perform the second drawing is placed in the using directive as in the following. Note that this is required when we want to use the rich functionalities of GDI+.
 

//Sample 00: Required Name Spaces

using System.Drawing.Drawing2D;

 

2. Then a Rectangle object is created and its size and position are filled in by the user-supplied values.
 

//Sample 01: Create the rect object.

Rectangle rect = new Rectangle();

rect.X = Int32.Parse(txtX.Text);

rect.Y = Int32.Parse(txtY.Text);

rect.Width = Int32.Parse(txtWidth.Text);

rect.Height = Int32.Parse(txtHeight.Text);

 

3. The black screen that you see in the sample application screenshot is a Panel Control. The CreateGraphics method will return the graphics object. You can use this method on any window object like Panel, Form or even controls like TextBox, listbox and so on. In our case, we asked the Panel Control to retrieve the Graphics object from it. And this object is stored in grp of type Graphics. Once the Graphics object is ready, a Pen is created with a color of Goldenrod, that is a preset color. You can see all the present color by typing Color dot. The following is the code:
 

//Sample 02: Get the Graphics from the Canvas(Panel) and Create the pen

Graphics grp = DrawingCanvas.CreateGraphics();

Pen pen = new Pen(Color.Goldenrod);

 

4. Before performing the Drawing (note that we write all the code in the Draw Button click handler), we clear any previously drawing by calling the Clear method of the Graphics object. Then the Rectangle is drawn with the user-supplied Rectangle demotions.
 

//Sample 03: Clear the Graphics and Draw Rectangle

grp.Clear(Color.Black);

grp.DrawRectangle(pen, rect);

 

Test Run 1: The video explains how the sample looks when the user feeds various values for the Rectangle. You can learn how Position and Size of Rectangle are used in drawing a rectangle in the following video.

 

Video 1: Test Run 1 - Drawing the Rectangle - Watch Here

 

5. The GDI+ Pen

 

Using the pen object we can define the color and its thickness. In our example application, controls marked by the number 3 are used to create a pen. In the previous section we created a pen just by specifying the color. This line of code is expanded to use the user selection on the form. Let us have look at the code for creating and using the Pen object:

 

1. First two variables are declared. The variable pencolor is used to specify the color of the pen and this variable will be filled with the user-selected color. The variable thickness specifies the pen thickness when we create the pen object.

 

//Sample 03: Create the Pen

Color pencolor;

int thickness;

 

2. Based on the user-selected Pen color using the Radio buttons, the pencolor variable is filled using predefined color values such as the "Color.Pink". The code is below:

 

//3.1: Decide Pen Color

if (radGolden.Checked == true)

    pencolor = Color.PaleGoldenrod;

else

    pencolor = Color.Pink;

 

3. Similarly, the thickness value is also filled by the user-selected line thickness combo boxvalue. The pen thickness in our example has three standard thicknesses, but you can specify any float value to create a pen thickness. The following is the code that stored the pen thickness:

 

//3.2: Decide Pen Thickness

if (rad1.Checked == true)

    thickness = 1;

else if (rad5.Checked == false)

    thickness = 3;

else

    thickness = 5;

 

4. Finally a pen object is created using the pencolor and thickness variables populated previously. This pen object can be supplied to Graphics functions so that the function uses this new pen whenever it performs a line drawing.

 

Pen pen = new Pen(pencolor, thickness);

 

The following is some of the Pen and a look at the lines formed by the Rectangle:

Pic02.jpg

 

Video 2: Creating a Pen - Watch Here

 

6. The GDI+ Brushes

 

In this example show various types of Brushes. Imagine a brush that you use to paint the walls of your house. The GDI+ brushes can also be used similar to this. We draw something using the pens that define the outer lines and then paints (using a brush) the region inside the region formed by the pens. But you are not as limited as for a brush that can be used only with pens.

 

The types of brush that you are going to see here are:
 

1. Simple Solid Brush

2. Gradient Brush

3. Patterned Brush

 

The Simple Solid brush fills the color in a plain solid color. The Gradient Brush fills colors between two colors applying the linear transformation from one color to another color. The hatch brushes fills the region with a given pattern. All these types of brushes in effect are shown in the following picture:

 

Pic03.jpg

 

OK. Let us see, how do we do it. 

 

1. The following is the CheckedChanged event handler for the checkbox marked as four in the first picture of the article. In this handler we decide to enable or disable the entire GroupBox that belongs to brushes.
 

//Sample 05: Enable the Brush Group Box

private void chkBrushEnable_CheckedChanged(object sender, EventArgs e)

{

    if (chkBrushEnable.Checked  == true)

        grpBrush.Visible = true;

    else

        grpBrush.Visible = false;

}

 

2. During the Form load, by default only the Solid brush option will be displayed. The user should check the Advanced Brush check box to enable the Gradient/Hatch Brush options. This code is below:
 

//Sample 06: Disable Advanced Brush Option

private void frmRectDraw_Load(object sender, EventArgs e)

{

    grpBrushAdv.Visible = false;

}

 

3. When the Advanced brush is displayed, the solid brush is hidden. In the same way, when the solid brush is displayed the advanced brush is hidden. This is done through the CheckedChanged event handler of the Advanced Brush check box. The code for that is shown below:
 

//Sample 07: To show or Hide Advanced brush option

private void chkAdvBursh_CheckedChanged(object sender, EventArgs e)

{

    if (chkAdvBursh.Checked == true)

    {

        grpBrushAdv.Visible = true;

        grpBrushSolid.Visible = false;

    }

    else

    {

        grpBrushAdv.Visible = false;

        grpBrushSolid.Visible = true;

    }

}

 

4. In the example application screenshot, the control item marked as 7 is a Label Control. This label control is used as the toggle button that alternates between Gradient and Hatch. When the control label shows as Gradient then the user will see controls relevant to Gradient Brush. The same is also true for the Hatch brush. We specify various captions for the color based radio buttons based on the current brush mode (Gradient or Hatch). The controls specific to the hatch brush will be shown/hidden based on the current brush mode. This kind of work is done in the click event handler for the Label control:
 

//Sample 08: Show the controls relevent for Hatch brush or

// Gradient Brush

private void lblHatchGr_Click(object sender, EventArgs e)

{

    if (lblHatchGr.Text == "Gradient")

    {

        lblHatchGr.Text = "Hatch";

        lblHatPat.Visible = true;

        radHatTypeHorizontal.Visible = true;

        radHatTypeVerticle.Visible = true;

        radHatTypeWave.Visible = true;

        radHatTypeHorizontalBrick.Visible = true;

        HatchGB1.Text = "Forecolor";

        HatchGB2.Text = "BackColor";

    }

    else

    {

        lblHatchGr.Text = "Gradient";

        lblHatPat.Visible = false;

        radHatTypeHorizontal.Visible = false;

        radHatTypeVerticle.Visible = false;

        radHatTypeWave.Visible = false;

        radHatTypeHorizontalBrick.Visible = false;

        HatchGB1.Text = "From";

        HatchGB2.Text = "To";

    }

}

 

5. The following is the function GetSolidBrushColor_FromUI that gets the color for the solid brush. This function reads the user-selected radio button for the solid brush color and assigns that to the out parameter passed in as color. Note that the out parameter guarantees the caller that the function will definitely assign a value in the color parameter and the caller does not need to initialize the value. The function is below:
 

//Sample 09: Get Solid Brush color from UI

private void GetSolidBrushColor_FromUI(out Color color)

{

    if (radSolBrRed.Checked == true)

        color = Color.Red;

    else if (radSolBrGreen.Checked == true)

        color = Color.Green;

    else

        color = Color.Blue;

}

 

6. Look at the sample application screenshot labeled at 6, the GroupBox names "From" and "To" will be changed to ForeColor and BackColor when the Brush mode changes from Gradient to Hatch. The function shown below will return the color values from the same Radio Buttons that is under these two sets of Radio Groups that change their name based on the brush mode:
 

//Sample 10: Get Color1 and Color2 from UI

private void Get_Col1_Col2(ref Color color1, ref Color color2)

{

    if (radhatCol1Blue.Checked == true)

        color1 = Color.Blue;

    else

        color1 = Color.Yellow;

 

    if (radHatCol2Green.Checked == true)

        color2 = Color.Green;

    else

        color2 = Color.Yellow;

}

 

7. The Inflate_Rect function written below will diminish the rectangular dimensions based on the current pen thickness. Note that the function takes the parameter as the reference type so the caller will expect the changes in the supplied rectangular dimensions. So we had looked at some of the helper functions written for the sample. Let us go the Hatch brush and filling techniques.
 

//Sample 11: Reduce rectangular dimension

private void Inflate_Rect(ref Rectangle rect)

{

    int inflate_to;

    int thickness;

 

    if (rad1.Checked == true)

        thickness = 1;

    else if (rad5.Checked == false)

        thickness = 3;

    else

        thickness = 5;

 

    inflate_to = thickness;

 

    rect.X = rect.X + inflate_to;

    rect.Y = rect.Y + inflate_to;

    rect.Width = rect.Width - inflate_to*2;

    rect.Height = rect.Height - inflate_to*2;

}

 

8. In the OnPaint handler after drawing the rectangle with the required Pen attributes, we fill the rectangle with the user selection of brush. Note that before making the Fill operation using the brush, the rectangle drawn using the Pen is inflated. You can create a solid brush by specifying the color. The graphics object supports many drawing functions with a Fill, say for example something like FillRectangle, FillEllipse and so on. In the following code we ensure the Advanced brush option is not selected by the user and then create a SolidBrush by specifying the solid fill color. Once the brush is created it can be used with the Graphics object. In our case we used the solid brush with the FillRectangle function. The following is the code that creates and uses the Solid Brush:
 

Inflate_Rect(ref rect);

if (chkAdvBursh.Checked == false)

{

    //Sample 12.1: Create Solid Brush and Perform the Fill

    //A. Declaration

    Color brush_color ;

    Brush Solid_brush = null;

    //B. Create Solid Brush

    GetSolidBrushColor_FromUI(out brush_color);

    Solid_brush = new SolidBrush(brush_color);

    //C. Fill the Rectangle

    grp.FillRectangle(Solid_brush, rect);

}

 

9. Based on the Toggle Label, we create the Gradient Brush. To create the gradient brush we need two colors as the gradient interpolates two colors in a linear way. Look at the previous picture for the gradient brush and in that the color interpolation is applied between blue and green in a horizontal way. In our example, we get both the colors required for the gradient effect by making a call to the function Get_Col1_Col2. Then we pass the "from_color" and "to_color" to the LinearGradientBrush contractor to create the Gradient_brush object. Once we have a Gradient Brush in hand we make a call to the function FillRectangle to get the Gradient effect. The code for this is shown below:

 

if (lblHatchGr.Text == "Gradient")

{

    //Sample 12.2: Create Gradient Brush and Perform the Fill

    //A. Declaration

    Color from_color= Color.White;

    Color to_color = Color.White;

    Brush Gradient_brush = null;

    //B. Create Gradient Brush

    Get_Col1_Col2(ref from_color, ref to_color);

    Gradient_brush = new LinearGradientBrush(rect, from_color, to_color,

        LinearGradientMode.Horizontal);

    //C. Fill the Rectangle

    grp.FillRectangle(Gradient_brush, rect);

}

 

In the code above, we asked the gradient to be applied horizontally by specifying "LinearGradientMode.Horizontal". The Gradient Modes are shown below:

 

 Pic04.jpg

 

10. In the else part of the Gradient Brush section we create the pattern brush to fill the rectangle. To see a pattern we should specify the background color and foreground color when creating the pattern brush. After having these colors (note that we used the same function call "Get_Col1_Col2"), the user-selected hatch pattern is stored in the style object. Refer to the MSDN to know other hatch patterns since there are much more patterns available. All this information is passed to the HatchBrush constructor to create the object Hatch_brush. Then as usual, this hatch brush is passed to the FillRectangle function of the Graphics object. The code is below that constructs the Pattern brush and uses that to fill the rectangle:
 

else

{

    //Sample 12.3: Create Hatch brush and perform the Fill

    //A. Declaration

    Color fore_color = Color.White;

    Color back_color = Color.White;

    Brush Hatch_brush = null;

    HatchStyle style;

 

    //B. Get Fore Color, Back Color. Also decide hatch style

    Get_Col1_Col2(ref fore_color, ref back_color);

 

    if (radHatTypeHorizontal.Checked == true)

        style = HatchStyle.Horizontal;

    else if (radHatTypeVerticle.Checked == true)

        style = HatchStyle.Vertical;

    else if (radHatTypeWave.Checked == true)

        style = HatchStyle.Wave;

    else

        style = HatchStyle.HorizontalBrick;

 

    //C. Create Pattern Brush

    Hatch_brush = new HatchBrush(style, fore_color, back_color);

 

    //D. Perform Drawing

    grp.FillRectangle(Hatch_brush, rect);

}

 

You will see how the Brush works in the sample from the following shown video.

 

Video 3: Creating and using Brushes - Watch Here

COMMENT USING

Trending up