Pen


The Pen object determines how lines are drawn. It determines the lines’ color, thickness, dash style, join style, and end cap style.

A program can explicitly create Pen objects, but often it can simply use one of the more than 280 pens that are predefined by the Pens class. For example, the following code draws a rectangle using a hot pink line that’s one pixel wide:

  gr.DrawRectangle(Pens.HotPink, 10, 10, 50, 50) 

Pen objects are scaled by transformations applied to a Graphics object, however, so the result is not necessarily one pixel thick. If the Graphics object applies a transformation that scales by a factor of 10, the resulting line will have thickness 10.

One solution to this problem is to create a new Pen object setting its thickness to 0.1, as shown in the following code. The thickness is scaled to 0.1 * 10 = 1.

  gr.DrawRectangle(New Pen(Color.HotPink, 0.1), 10, 10, 50, 50) 

Another solution is to create a pen with thickness 0. The GDI+ routines always draw lines that have 0 thickness as one pixel wide.

The Pen class provides several overloaded constructors, which are described in the following table.

Open table as spreadsheet

Constructors

Description

Pen(brush)

Creates a pen of thickness 1 using the indicated Brush. Lines are drawn as rectangles filled with the Brush. This makes the most sense for relatively thick lines, so the fill is visible. It produces sometimes irregular dashed or dotted results for thin lines.

Pen(color)

Creates a pen of thickness 1 using the indicated color.

Pen(brush, thickness)

Creates a pen with the indicated thickness (a Single) using a Brush.

Pen(color, thickness)

Creates a pen with the indicated thickness (a Single) using the indicated color.

The following table describes some of the Pen class’s most useful properties and methods.

Open table as spreadsheet

Property or Method

Purpose

Alignment

Determines whether the line is drawn inside or centered on the theoretical perfectly thin line specified by the drawing routine. See the section “Alignment” later in this chapter for examples.

Brush

Determines the Brush used to fill lines.

Color

Determines the lines’ color.

CompoundArray

Lets you draw lines that are striped lengthwise. See the section “CompoundArray” later in this chapter for examples.

CustomEndCap

Determines the line’s end cap. See the section “Custom Line Caps” later in this chapter for examples.

CustomStartCap

Determines the line’s start cap. See the section “Custom Line Caps” later in this chapter for examples.

DashCap

Determines the cap drawn at the ends of dashes. This can be Flat, Round, or Triangle.

DashOffset

Determines the distance from the start of the line to the start of the first dash.

DashPattern

An array of Singles that specifies a custom dash pattern. The array entries tell how many pixels to draw, skip, draw, skip, and so forth. Note that these values are scaled if the pen is not one pixel wide.

DashStyle

Determines the line’s dash style. This value can be Dash, DashDot, DashDotDot, Dot, Solid, or Custom. If you set the DashPattern property, this value is set to Custom. Note that the dashes and gaps between them are scaled if the pen is not one pixel wide.

EndCap

Determines the cap used at the end of the line. This value can be ArrowAnchor, DiamondAnchor, Flat, NoAnchor, Round, RoundAnchor, Square, SquareAnchor, Triangle, and Custom. If LineCap is Custom, you should use a CustomLineCap object to define the cap. Figure 21-1 shows the standard LineCap values.

LineJoin

Determines how lines are joined by a GDI+ method that draws connected lines. For example, the DrawPolygon and DrawLines methods use this property. This value can be Bevel, Miter, and Round. Figure 21-2 shows these values.

MultiplyTransform

Multiplies the Pen class’s current transformation by another transformation matrix. See the section “Pen Transformations” later in this chapter for more information and examples.

ResetTransform

Resets the Pen class’s transformation to the identity transformation. See the section “Pen Transformations” later in this chapter for more information and examples.

RotateTransform

Adds a rotation transformation to the Pen class’s current transformation. See the section “Pen Transformations” later in this chapter for more information and examples.

ScaleTransform

Adds a scaling transformation to the Pen class’s current transformation. See the section “Pen Transformations” later in this chapter for more information and examples.

SetLineCap

This method takes parameters that let you specify the Pen class’s StartCap, EndCap, and LineJoin properties at the same time.

StartCap

Determines the cap used at the start of the line. See the EndCap property for details.

Transform

Determines the transformation applied to the initially circular “pen tip” used to draw lines. The transformation lets you draw with an elliptical tip. See the section “Pen Transformations” later in this chapter for more information and examples.

TranslateTransform

Adds a translation transformation to the Pen class’s current transformation. Pen objects ignore any translation component in their transformations, so this method does has no effect on the Pen class’s final appearance and was probably added for consistency and completeness. See the section “Pen Transformations” later in this chapter for more information and examples.

Width

The width of the pen. This value is scaled if the pen is transformed either by its own transformation or by the transformation of the Graphics object that uses it.

image from book
Figure 21-1: The LineCap enumeration determines how a line’s endpoints are drawn.

image from book
Figure 21-2: The LineJoin enumeration determines how lines are joined.

The following sections describe some of the Pen class’s more confusing properties and methods.

Alignment

The Alignment property determines whether thick lines for closed curves are drawn inside or centered on the theoretical perfectly thin line specified by the drawing routine. This property can take the values Center or Inset.

The following code draws a circle with a thick white line and its pen’s Alignment set to Center. It then draws the same circle with a thin black line. Next, the code repeats these steps, drawing its thick white circle with Alignment set to Inset.

  Private Sub Form1_Paint(ByVal sender As Object, _  ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint     Using the_pen As New Pen(Color.LightGray, 20)         the_pen.Alignment = PenAlignment.Center         e.Graphics.DrawEllipse(the_pen, 25, 25, 100, 100)         e.Graphics.DrawEllipse(Pens.Black, 25, 25, 100, 100)         the_pen.Alignment = PenAlignment.Inset         e.Graphics.DrawEllipse(the_pen, 150, 25, 100, 100)         e.Graphics.DrawEllipse(Pens.Black, 150, 25, 100, 100)     End Using End Sub  

Figure 21-3 shows a more elaborate program that draws samples of all of the Alignment values.Notice that all of the Alignment values produce the same result as Center, except for the value Inset.

image from book
Figure 21-3: A Pen class’s Alignment property determines whether the line is drawn on or inside its theoretical perfectly thin line.

The Alignment property applies only to closed figures such as ellipses, rectangles, and polygons. Open figures such as line segments, arcs, and unclosed curves are always drawn centered.

CompoundArray

The CompoundArray property lets a program draw lines that are striped lengthwise. This property is an array of Single values that determine where the solid and empty parts of the line lie as a fraction of the line’s width. For example, an array containing the values {0.0, 0.25, 0.75, 1.0} makes the first quarter of the line solid (0.0–0.25), the next half of the line not drawn (0.25–0.75), and the last quarter of the line solid (0.75–1.0).

The following code demonstrates the CompoundArray property. It creates a thick pen, sets its CompoundArray property to draw a line with a thin empty stripe down the middle, and draws a line. Next, the code sets the CompoundArray property to draw three equally sized and spaced stripes, and draws a rectangle and circle. Finally, the code sets the Graphics object’s SmoothingMode property to AntiAlias, resets CompoundArray to draw a line with two thin empty stripes and draws another circle.

  Private Sub Form1_Paint(ByVal sender As Object, _  ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint     Using the_pen As New Pen(Color.Black, 10)         the_pen.CompoundArray = New Single() {0.0, 0.45, 0.55, 1.0}         e.Graphics.DrawLine(the_pen, 10, 20, 400, 20)         the_pen.CompoundArray = New Single() {0.0, 0.2, 0.4, 0.6, 0.8, 1.0}         e.Graphics.DrawRectangle(the_pen, 20, 50, 100, 100)         e.Graphics.DrawEllipse(the_pen, 150, 50, 100, 100)         the_pen.CompoundArray = New Single() {0.0, 0.1, 0.2, 0.8, 0.9, 1.0}         e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias         e.Graphics.DrawEllipse(the_pen, 300, 50, 100, 100)     End Using End Sub  

Figure 21-4 shows the result.

image from book
Figure 21-4: A Pen class’s CompoundArray property lets you draw lines that are striped lengthwise.

Custom Line Caps

The Pen class’s CustomEndCap and CustomStartCap properties let you define your own end caps for lines. To make a custom cap, make a GraphicsPath object that defines the cap’s drawing commands. This object should use a coordinate system where X increases to the left of the line, and Y increases in the direction of the line, as shown in Figure 21-5.

image from book
Figure 21-5: When building a custom line cap, X increases to the line’s left and Y increases in the line’s direction.

Next, create a CustomLineCap object, passing its constructor the GraphicsPath object. Pass the GraphicsPath as the first parameter if it defines a fill for the cap. Pass it as the second parameter if it defines drawn lines for the cap. Pass Nothing for the other parameter.

You can use the CustomLineCap object’s properties and methods to modify its appearance. For example, its StrokeJoin property determines the style used to join the lines in the GraphicsPath, and its Set?StrokeCaps method lets you specify the end caps for the lines in the GraphicsPath.

The following code shows an example. It defines an array of points that defines lines that make an X. It makes a GraphicsPath object and uses its AddLines method to add the lines to it. It then creates a CustomLineCap object, passing its constructor this GraphicsPath. The code makes a Pen and sets its CustomStartCap and CustomEndCap properties to the CustomLineCap object. It then draws four lines with different widths.

  Private Sub Form1_Paint(ByVal sender As Object, _  ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint     ' Make a GraphicsPath that draws an X.     Dim pts() As Point = { _         New Point(-2, -2), _         New Point(0, 0), _         New Point(-2, 2), _         New Point(0, 0), _         New Point(2, 2), _         New Point(0, 0), _         New Point(2, -2) _     }     Using cap_path As New GraphicsPath         cap_path.AddLines(pts)         ' Make the CustomLineCap.         Using x_cap As New CustomLineCap(Nothing, cap_path)             ' Draw some lines with x_cap.             Using the_pen As New Pen(Color.Black, 1)                 the_pen.CustomStartCap = x_cap                 the_pen.CustomEndCap = x_cap                 e.Graphics.DrawLine(the_pen, 50, 10, 200, 10)                 the_pen.Width = 5                 e.Graphics.DrawLine(the_pen, 50, 40, 200, 40)                 the_pen.Width = 10                 e.Graphics.DrawLine(the_pen, 50, 100, 200, 100)                 the_pen.Width = 20                 e.Graphics.DrawLine(the_pen, 50, 200, 200, 200)             End Using         End Using     End Using End Sub 

Figure 21-6 shows the result.

image from book
Figure 21-6: This program uses a CustomLineCap that draws an X at the end of lines.

Pen Transformations

The Pen class has properties and methods that let you define a transformation. The Pen class applies this transformation to its initially circular tip when drawing lines. The Pen class ignores any translation component in the transformation, so the result is always an ellipse. (With some thought, you can probably convince yourself that any combination of scaling and rotation applied to a circle always gives an ellipse.) When the program draws with the transformed pen, its lines may have thick and thin elements similar to the ones you get when you draw with a calligraphy pen.

The following code uses a transformed Pen to draw a circle. It begins by defining some constants to make working with the circle easier. It defines the circle’s center (Cx, Cy) and its radius R. It also defines a constant to represent the Pen’s Width. Next, the program creates a new Pen with the desired width. It applies a scaling transformation to the pen, scaling by a factor of 4 in the Y direction. For the purposes of scaling Pens, the X and Y directions match those on the screen. This transformation stretches the Pen class’s tip vertically on the screen. Next, the program rotates the Pen’s tip by 45 degrees.

The program sets the Graphics object’s SmoothingMode property to AntiAlias and draws a circle centered at (Cx, Cy) with radius R.

Next, the program draws some ellipses showing where the Pen’s tip was while it was drawing the circle. It starts by applying the same scaling and rotation transformations to the Graphics object. The program will later draw a circle with a diameter equal to the line’s thickness and centered at the origin. These transformations give the circle the same shape as the Pen class’s transformed tip. The final step is to translate these ellipses so that they lie along the path of the circle drawn earlier with the transformed Pen class.

The program uses a loop to make an angle vary from 0 to 2 * PI radians in steps of PI / 8. For each angle, the code saves the Graphics object’s state so it doesn’t lose the scaling and rotation it already applied. It then applies a translation transformation to move the origin to a point on the circle drawn earlier. The center of the circle is at (Cx, Cy). The points on the circle are offset from that point by R * Cos(angle) in the X direction and R * Sin(angle) in the Y direction.

Having defined all these transformations, the program draws a white ellipse centered at the origin and with diameter matching the Pen class’s width. The transformations scale, rotate, and translate the ellipse to match one of the Pen class’s tip positions while it drew the large ellipse. Finally, the code restores the saved graphics state so it is ready for the next trip through the loop.

  Private Sub Form1_Paint(ByVal sender As Object, _  ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint     Const Cx As Integer = 120     Const Cy As Integer = 120     Const R As Integer = 100     Const PEN_WID As Integer = 10     ' Draw a circle with a transformed Pen.     Using the_pen As New Pen(Color.Black, PEN_WID)         the_pen.ScaleTransform(1, 4, MatrixOrder.Append)         the_pen.RotateTransform(45, MatrixOrder.Append)         e.Graphics.SmoothingMode = SmoothingMode.AntiAlias         e.Graphics.DrawEllipse(the_pen, Cx - R, Cx - R, R * 2, R * 2)     End Using     ' Draw "Pen tips" on the circle.     e.Graphics.ScaleTransform(1, 4, MatrixOrder.Append)     e.Graphics.RotateTransform(45, MatrixOrder.Append)     For angle As Single = 0 To 2 * PI Step PI / 8         Dim graphics_state As GraphicsState = e.Graphics.Save         e.Graphics.TranslateTransform( _             CSng(Cx + R * Cos(angle)), _             CSng(Cy + R * Sin(angle)), _             MatrixOrder.Append)         e.Graphics.DrawEllipse(Pens.White, _             -PEN_WID / 2, -PEN_WID / 2, PEN_WID, PEN_WID)         e.Graphics.Restore(graphics_state)     Next angle End Sub  

Figure 21-7 shows the result. The small white ellipses show the positions that the Pen class’s tip took while drawing the large black ellipse. This picture should give you a good intuition for how transformed Pens work.

image from book
Figure 21-7: The white circles show where the Pen class’s transformed tip was as it drew the large black circle.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

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