Drawing with Pens

Drawing with Pens

As mentioned, pens are used with the Graphics class to draw lines and other figures. In the examples earlier in this chapter, the SystemPens class has been used to obtain references to Pen objects initialized with the same color as client window text. In this section, we’ll examine the SystemPens class more closely and you’ll learn how to use the Pens class and the Pen class directly to create Pen objects in a variety of styles and colors.

Using the SystemPens and Pens Classes

Just like the SystemBrushes class discussed earlier in this chapter, the SystemPens class is used to create pens that match user interface components and system colors. The static properties exposed by the SystemPens class each return a reference to a shared Pen object. In earlier examples, Pen objects were created that were compatible with the window text color selected by the user. You can also create Pen objects that follow other user preferences, as shown here:

Pen highlightPen = SystemPens.HighlightText;

This example creates a Pen object that’s initialized to the user’s preferred color for highlighted text. A complete list of the static SystemPens properties used to create pens based on user preferences is provided in Table 14-7.

The properties in Table 14-7 are similar to the properties exposed by the SystemBrushes class listed in Table 14-4. They differ because pens and brushes typically are used to draw with different color schemes. Pens are often used to draw lines and shadow effects, whereas brushes are often used to fill areas with a color or a pattern. For example, there’s no Window property for the SystemPens class because pens aren’t frequently used to draw in colors that match the client area. As with the SystemBrushes class, the SystemPens class can be used to create pens based on a Color value passed as a parameter to the SystemPens.From­System­Color method, as shown here:

Pen clientAreaPen = SystemPens.FromSystemColor(SystemColors.Window);

All the Pen references you’ll get from the SystemPens class (as well as from the Pens class, which we’ll get to shortly) have an initial width of 1 pixel. You don’t own the Pen objects, so you can’t modify them. If you need alternative widths or styles, you’ll need to create your pens using the Pen class, which will be discussed in the next section.

An alternative to passing a named color to the SystemPens class is to use the Pens class. The Pens class is organized much like the SystemPens class in that it exposes a large number of static methods that are used to create Pen objects. For example, to create a red pen, you call the static Pens.Red method, like this:

Pen warningPen = Pens.Red; 

All told, there are 141 static methods in the Pens class, so again there isn’t space to list them all here. The Pens class follows the same naming convention as the Color and Brushes classes, however, so if you know the named color, you can create your Pen object directly, without extracting the color first.

Using the Pen Class

The objective behind using the SystemPens and Pens classes is to obtain a reference to a Pen object. Up to now, you’ve seen the Pen class used to draw lines and figures; in this section, we’ll examine the various methods and properties exposed by the Pen class that enable you to manage the characteristics of the lines drawn using a Pen object.

Creating Pens

In addition to using the SystemPens and Pens classes to fetch references to Pen objects, you can also create them using the Pen class directly. There are four constructors used to create Pen objects. These constructors enable you to specify a color or a brush that will be used to define the pattern drawn by the pen, as well as an optional width. The first constructor is used to create a pen of a specific color with an initial width of 1 pixel, as shown here:

Pen clearBluePen = new Pen(Color.FromArgb(40, 50, 50, 255)); 

You can also specify the width when constructing a Pen object with a Color value, as shown here:

Pen clearBluePen = new Pen(Color.FromArgb(40, 50, 50, 255), 20.0f);

Alternatively, you can use a Brush object to supply a pattern for your new Pen, using code such as this:

HatchBrush _horizontalBrickBrush = null;
HatchBrush _diagonalBrickBrush = null;
Pen        _diagonalThinBricks = null;
Pen        _horizontalThinBricks = null;

    

public MainForm()
{
    
    

    _horizontalBrickBrush = new HatchBrush(HatchStyle.HorizontalBrick,
                                           Color.Gray,
                                           Color.Firebrick);
    _diagonalBrickBrush = new HatchBrush(HatchStyle.DiagonalBrick,
                                         Color.Gray,
                                         Color.Firebrick);
    _diagonalThinBricks = new Pen(_diagonalBrickBrush);
    _horizontalThinBricks = new Pen(_horizontalBrickBrush);
} 

This code creates instances of HatchBrush with the DiagonalBrick and HorizontalBrick hatch styles and then uses the brushes to create two pens that are each 1 pixel wide. Because the width of the pens is much smaller than the brick pattern, the lines drawn with these pens will have a striped appearance. The fourth version of the Pen constructor enables you to specify a width for the pen that makes the brick pattern more apparent, as shown here:

Pen_diagonalThickBricks = new Pen(_diagonalBrickBrush, 10.0f);
Pen_horizontalThickBricks = new Pen(_horizontalBrickBrush, 10.0f); 

Figure 14-12 shows an example using these Pen objects to draw figures in a Windows Form client area.

Figure 14-12.
Several pens initialized with hatch brushes.
Taking Advantage of Pen Styles

The Pen class exposes styles as properties that can be changed dynamically without having to re-create the Pen object each time a property needs to be altered. The most commonly used properties from the Pen class are as follows:

  • Alignment  Specifies the position of the drawn line in relation to the curve or figure coordinates.

  • Brush  Specifies a brush used to provide the pattern and color for this pen.

  • Color  Specifies a color used for this pen.

  • EndCap  Specifies the shape rendered at the end of the line or curve, using a value from the LineCap enumeration. The default value is LineCap.Flat.

  • LineJoin  Specifies how sequences of lines are joined, using a value from the LineJoin enumeration.

  • MiterLimit  Specifies the maximum permitted ratio between line width and miter thickness before clipping occurs. This property applies only if the LineJoin property is set to LineJoin.MiterClipped. The default value is 10.0f.

  • PenType  Returns a value from the PenType enumeration that describes the Pen object.

  • StartCap  Specifies the shape rendered at the start of the line, using a value from the LineCap enumeration. The default value is LineCap.Flat.

  • Width  Specifies the width of the line drawn with the pen.

The Alignment property specifies how screen real estate is consumed by a line drawn with the pen. The default value of PenAlignment.Center draws the line centered over the line boundary. A value of PenAlignment.Inset draws the line inside the line that forms the boundary of a curve or a figure.

The LineCap enumeration is used by the StartCap and EndCap properties to draw the ends of each line. Some values in the LineCap enumeration include Anchor in their name, which indicates that the LineCap style draws an anchored end for the line. Anchor values cause the line end to be drawn wider than the line’s width. This type of LineCap style is useful when you want to emphasize the endpoints of the line. To determine whether a LineCap style is one of the anchor values, you can use AnchorMask, a value from the LineCap enumeration, as shown here:

if((clearBluePen.EndCap & LineCap.AnchorMask) > 0)
{
    // EndCap has one of the anchor styles.
    
    

As mentioned, the LineCap enumeration is used to specify how the ends of each line are drawn. The LineCap enumeration values are provided in Table 14-8.

Table 14-8.  LineCap Enumeration Values

Value

Description

AnchorMask

A mask value used to test whether a LineCap value specifies an anchor cap.

ArrowAnchor

An arrow-shaped anchor is drawn for the line cap.

Custom

A custom end cap specified by the application is drawn.

DiamondAnchor

A diamond-shaped anchor is drawn for the line cap.

Flat

The default value; no cap is drawn.

NoAnchor

Same as LineCap.Flat; no anchor is drawn.

Round

A round line cap is drawn.

RoundAnchor

A large round line cap is drawn.

Square

A square line cap is drawn.

SquareAnchor

A large square anchor line cap is drawn.

Triangle

A triangle-shaped line cap is drawn.

The LineJoin property uses the values from the LineJoin enumeration to control how line endpoints are joined together when drawing figures with methods such as DrawPolygon or when several lines are drawn with a single call to the DrawLines method. This property isn’t used when you’re drawing multiple lines by making multiple calls to the DrawLine method. The LineJoin enumeration values are provided in Table 14-9.

Table 14-9.  LineJoin Enumeration Values

Value

Description

Bevel

The lines are joined in a beveled edge.

Miter

The lines are joined as if mitered, with the outside edges of the lines extended until they meet.

MiterClipped

The lines are extended just like the LineJoin.Miter style, except that the length of the mitered join is subject to clipping if it extends past the length allowed by the Pen object’s MiterLimit property.

Round

The lines are joined with a rounded corner.

The PenType property returns a value from the PenType enumeration that describes how the Pen object determines its color or pattern. This read-only value contains information about the underlying brush or color that the Pen object is currently using. The PenType enumeration values are listed in Table 14-10.

Table 14-10.  PenType Enumeration Values

Value

Description

HatchFill

The pen uses a hatch brush.

LinearGradient

The pen uses a linear gradient brush.

PathGradient

The pen uses a path gradient brush.

SolidColor

The pen uses a color or a SolidBrush object.

TextureFill

The pen uses a texture brush.

Drawing Dashed Lines with Pens

The Pen class can be used to create pens that will draw dashed lines. There are three properties that are used to control how dashes are drawn.

  • DashOffset  Specifies the distance from the start of the line to the start of the dash pattern

  • DashStyle  Specifies the pattern of the dashes, using a value from the DashStyle enumeration

  • DashPattern  Specifies an array of floating-point values that define a pattern of dots and dashes used when the DashStyle property is set to DashPattern.Custom

The DashStyle property uses values from the DashStyle enumeration to select from among predefined dash styles or to specify that a custom dash pattern is to be used. The DashStyle enumeration values are provided in Table 14-11.

The DashPattern property accepts an array of floating-point values, with each element alternatively specifying the length of each dash and space, like this:

clearBluePen.DashStyle = DashStyle.Custom;
clearBluePen.DashPattern = new float [] {   0.5f,
                                            0.3f,
                                            1.0f,
                                            0.5f };

The values passed to the DashPattern property are multiplied by the pen’s width to determine the actual spacing of dashes and spaces.



Part III: Programming Windows Forms