Pens


Whereas the Brush classes are used to fill shapes, the Pen class is used to frame shapes . The interesting members are shown here:

 sealed class Pen : MarshalByRefObject, ICloneable,  IDisposable {   // Constructors   public Pen(Brush brush);   public Pen(Brush brush, float width);   public Pen(Color color);   public Pen(Color color, float width);   // Properties   public PenAlignment Alignment { get; set; }   public Brush Brush { get; set; }   public Color Color { get; set; }   public float[] CompoundArray { get; set; }   public CustomLineCap CustomEndCap { get; set; }   public CustomLineCap CustomStartCap { get; set; }   public DashCap DashCap { get; set; }   public float DashOffset { get; set; }   public float[] DashPattern { get; set; }   public DashStyle DashStyle { get; set; }   public LineCap EndCap { get; set; }   public LineJoin LineJoin { get; set; }   public float MiterLimit { get; set; }   public PenType PenType { get; }   public LineCap StartCap { get; set; }   public float Width { get; set; }   // Transformation members elided...   // Methods   public void SetLineCap(...); } 

Pens have several interesting properties, including a width, a color or a brush, start and end cap styles, and a dash pattern for the line itself. One note of interest is that the width of a pen is specified in the units of the underlying Graphics being drawn on (more information about Graphics units is available in Chapter 6: Advanced Drawing). However, no matter what the underlying units, a pen width of 0 always translates into a width of 1 physical unit on the underlying Graphic surface. This lets you specify the smallest visible pen width without worrying about the units of a particular surface.

You'll notice that the Pen class is sealed. This means that it can't be used as a base class for further penlike functionality. Instead, each pen has a type that governs its behavior, as determined by the PenType enumeration:

 enum PenType {   SolidColor, // Created from a color or a SolidBrush   TextureFill, // Created from a TextureBrush   HatchFill, // Created from a HatchBrush   LinearGradient, // Created from a LinearGradientBrush   PathGradient, // Created from a PathGradientBrush } 

If you're interested in common, solid-color pens, the 141 named pens are provided as static Pen properties on the Pens class, and 15 system pens are provided as static Pen properties on the SystemPens class, providing the same usage as the corresponding Brushes and SystemBrushes classes. As with SystemBrushes, the FromSystemColor method of the SystemPens class returns a pen in one of the system colors that's managed by .NET.

Line Caps

In addition to their brushlike behavior, pens have behavior at ends and joints and along their length that brushes don't have. For example, each end can have a different style, as determined by the LineCap enumeration shown in Figure 4.9.

Figure 4.9. Examples from the LineCap Enumeration

All these lines were generated with a black pen of width 12 passed to the Graphics.DrawLine method. The white line of width 1 in the middle is drawn using a separate call to Graphics.DrawLine to show the two end points that define the line. Each black pen is defined with the EndCap property set to a value from the LineCap enumeration:

 using( Pen pen = new Pen(Color.Black, 12) ) {   pen.EndCap = LineCap.Flat; // default   g.DrawLine(pen, x, y + height*2/3, x + width*2/3, y + height*2/3);   g.DrawLine(whitePen, x, y + height*2/3, x + width*2/3, y + height*2/3);   ... } 

The default line cap style is flat, which is what all the StartCap properties are set to. You'll notice some familiar line cap styles, including flat, round, square, and triangle, which have no anchor, as well as arrow, diamond, round, and square, which have anchors. An anchor indicates that part of the line cap extends beyond the width of the pen. The difference between square and flat, on the other hand, dictates whether the line cap extends beyond the end of the line (as square does, but flat does not).

You can manage these kinds of drawing behaviors independently by using the LineCap.Custom enumeration value and setting the CustomStartCap or CustomEndCap field to a class that derives from the CustomLineCap class (from the System.Drawing.Drawing2D namespace). The custom line cap in Figure 4.9 shows a pen created using an instance of the AdjustableArrowCap class, the only custom end cap class that .NET provides:

 using( Pen pen = new Pen(Color.Black, 12) ) {  pen.EndCap = LineCap.Custom;   // width and height of 3 and unfilled arrow head   pen.CustomEndCap = new AdjustableArrowCap(3f, 3f, false);  ... } 

Dashes

In addition to the ends having special styles, a line can have a dash style, as defined by the DashStyle enumeration, shown in Figure 4.10.

Figure 4.10. Examples Using the DashStyle Enumeration

Each of the lines was created by setting the DashStyle property of the pen. The DashStyle.Custom value is used to set custom dash and space lengths, where each length is a multiplier of the width. For example, the following code draws the increasing length dashes shown in Figure 4.10 with a constant space length:

 using( Pen pen = new Pen(Color.Black, 12) ) {  pen.DashStyle = DashStyle.Custom;   // Set increasing dashes and constant spaces   pen.DashPattern =   new float[] { 1f, 1f, 2f, 1f, 3f, 1f, 4f, 1f, };  g.DrawLine(     pen, x + 10, y + height*2/3, x + width - 20, y + height*2/3); } 

If you'd like to exercise more control over your custom dash settings, you can set the DashCap property on the pen to any of the values in the DashCap enumeration, which is a subset of the values in the LineCap enumeration with only Flat (the default), Round, and Triangle.

To exercise more control over the line itself, in addition to dash settings, you can define compound pens using the CompoundArray property. This allows you to provide lines and spaces in parallel to the lines being drawn instead of perpendicularly, as dash settings do. For example, Figure 4.11 was drawn with a pen set up this way:

 using( Pen pen = new Pen(Color.Black, 20) ) {  // Set percentages of width where line starts, then space starts,   // then line starts again, etc. in alternating pattern   pen.CompoundArray =   new float[] { 0.0f, 0.25f, 0.45f, 0.55f, 0.75f, 1.0f, };  g.DrawRectangle(pen, new Rectangle(...)); } 
Figure 4.11. A Single Rectangle Drawn with a Pen Using a Compound Array

Alignments

Most of the examples, including Figure 4.11, have shown pens of width greater than 1. When you draw a line of width greater than 1, the question is, where do the extra pixels go ”above the line being drawn, below it, or somewhere else? The default pen alignment is centered , which means that half the width goes inside the shape being drawn and the other half goes outside. The alignment can also be inset , which means that the entire width of the pen is inside the shape being drawn, as shown in Figure 4.12.

Figure 4.12. Pen Alignment Options

In Figure 4.12, both ellipses are drawn using a rectangle of the same dimensions (as shown by the red line), but the different alignments determine where the width of the line is drawn. There are actually several values in the PenAlignment enumeration, but only Center and Inset are currently supported, and Inset is used only for closed shapes (an open figure has no "inside").

Joins

One final consideration you'll have when drawing figures that have angles is what to do with the line at the angle. In Figure 4.13, the four values in the PenJoin enumeration have been set in the Pen class's LineJoin property before the rectangles were drawn (again, a white line of width 1 is used to show the shape being drawn).

Figure 4.13. Sample PenJoin Values

Notice in Figure 4.13 that each corner provides a different join. The one exception is MiterClipped, which changes between Bevel and Miter dynamically based on the angle of the corner and the limit set by the MiterLimit property.

Creating Pens from Brushes

So far in this section on pens, all the examples have used solid-color pens. However, you can also create a pen from a brush. For example, Figure 4.14 shows an image you first encountered in Chapter 1: Hello, Windows Forms.

Figure 4.14. Creating a Pen from a LinearGradientBrush

The pen used to draw the lines in Figure 4.14 was created from a LinearGradientBrush:

 using( LinearGradientBrush brush =           new LinearGradientBrush( this.ClientRectangle,                                   Color.Empty, // ignored                                   Color.Empty, // ignored                                   45) ) {   ColorBlend blend = new ColorBlend();   blend.Colors = new Color[] { Color.Red, Color.Green, Color.Blue };   blend.Positions = new float[] { 0, .5f, 1 };   brush.InterpolationColors = blend;  using( Pen pen = new Pen(brush) ) {  ...  }  } 

The ability to create a pen from a brush lets you use any effect you can create using the multitude of brushes provided by System.Drawing.



Windows Forms Programming in C#
Windows Forms Programming in C#
ISBN: 0321116208
EAN: 2147483647
Year: 2003
Pages: 136
Authors: Chris Sells

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net