RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Beautify Your UIs with Perfect Pen and Brush Control : Page 2

Spice up your interfaces by taking full advantage of the Pen and Brush classes capabilities in the .NET Framework. Learn to create dashed and striped lines, control line joins, and use brushes to create interesting patterns and gradients.

Custom Line Caps
So far, modifying Pens has been fairly easy. You need to set only a property or two to use different line joins, end caps, dash styles, and dash caps. But custom end caps are a bit harder.

To make a custom end cap, make a GraphicsPath object and use its methods to add whatever drawing commands you like to the end cap—lines, ellipses, arcs, whatever. Next create a new CustomLineCap object, passing the GraphicsPath you built to its constructor. Finally set the Pen's CustomStartCap or CustomEndCap property to the CustomLineCap object.

One complicating factor is that the GraphicsPath that defines the end caps uses a special coordinate system that is relative to the line's orientation. This lets your end caps rotate as needed to match up with the line but it does make it a bit harder to figure out how to build the GraphicsPath object.

If you think of yourself as standing on the end of the line looking toward the line (so the line is in front of you), then the X coordinate increases to your right and the Y coordinate increases behind you. (This almost makes sense if you think of the line as running from the bottom of your screen to the top because on the screen X coordinates increase to the right and Y coordinates increase toward the bottom.)

It's confusing enough that you may want to draw the result you want on a piece of paper and draw the coordinates on top to help figure out what parameters to pass into the GraphicsPath methods.

The sample program "CustomEndCaps" uses the following code to draw the line shown in Figure 5.

Figure 5. Drawing Custom End Caps: The sample program "CustomEndCaps" shows sample start and end caps.
   Using the_pen As New Pen(Color.Blue, 10)
       ' Make the start cap.
       Dim start_path As New GraphicsPath()
       start_path.AddLine(0, 0, 2, 0)
       start_path.AddLine(0, 0, 0, 4)
       Dim start_line_cap As New CustomLineCap( _
          Nothing, start_path)
       the_pen.CustomStartCap = start_line_cap
       ' Make the end cap.
       Dim end_path As New GraphicsPath()
       end_path.AddLine(0, 0, 2, -2)
       end_path.AddLine(0, 0, -2, -2)
       Dim end_line_cap As New CustomLineCap(Nothing, end_path)
       the_pen.CustomEndCap = end_line_cap
       ' Draw a sample.
       Dim x1 As Integer = 50
       Dim x2 As Integer = 250
       Dim y As Integer = 50
       e.Graphics.DrawLine(the_pen, x1, y, x2, y)
   End Using
For the start cap, the code makes a GraphicsPath and adds a short line in the X direction and a longer line in the Y direction. You can see them on the left in Figure 5. Take a moment to visualize yourself standing on the end of the line (where the two smaller segments meet) and looking to the right along the line's length. X increases to your right and Y increases behind you.

To draw its end cap, the program makes another GraphicsPath object and adds lines angling in the negative Y direction, which is back along the line's length, and in both the positive and negative X directions. That makes the arrowhead on the right in Figure 5.

Compound Pens
Perhaps the least known feature of the Pen class is the ability to make compound Pens. A compound Pen draws lines that are striped lengthwise—sort of like dashes along the line's width instead of its length.

To create a compound Pen, make an array of Singles with values between 0.0 and 1.0. The values indicate the fractions of the distance across the width of the line where drawing should start and stop.

For example, the values 0.0, 0.45, 0.55, 1.0 indicate that the line should be drawn from 0.0 to 0.45 of the width, not drawn from 0.45 to 0.55, and drawn from 0.55 to 1.0. The result is a line that has a thin empty stripe down its middle 10 percent.

Set the Pen's CompoundArray property to this array and draw as usual. The following code draws an ellipse with a thick blue pen that has an undrawn stripe down its middle:

   Using blue_pen As New Pen(Color.Blue, 20)
       Dim compound_array As Single() = {0.0, 0.45, 0.55, 1.0}
       blue_pen.CompoundArray = compound_array
       e.Graphics.DrawEllipse(blue_pen, _
           New Rectangle(20, 20, 100, 100))
   End Using
The program "CompoundPens" (see its output in Figure 6), uses several compound Pens. The outer blue ellipse uses compound array values 0.0, 0.1, 0.2, 0.8, 0.9, 1.0. The smaller green ellipse inside the blue one uses array values 0.0, 0.4, 0.5, 1.0 and has its DashStyle set to Dot. Notice the small gap on the left where two dots don't quite meet each other.

The star in Figure 6 is drawn with two Pens. The first is red and uses the array values 0.0, 0.5, 1.0, 1.0; it draws only the first side of the line. The second Pen is orange and uses the values 0.0, 0.0, 0.5, 1.0 to draw the second side of the line.

Figure 6. Compound Pens: You can use compound pens to draw "striped" lines in which you control the width of the stripes.
Figure 7. Antialiasing: The ellipse on the right sets the Pen's SmoothingMode property to AntiAlias, resulting in a noticeably smoother figure.
Smooth Lines
I want to mention one final Pen technique before moving on to Brushes. You can use a Graphics object's SmoothingMode property to determine whether it uses anti-aliasing to make the edges of drawn lines smoother.

For example, the following code draws an ellipse. It then sets SmoothingMode to AntiAlias and draws another ellipse. As you can see in Figure 7, the second ellipse (on the right) is noticeably smoother.

   Using the_pen As New Pen(Color.Black, 10)
       ' Draw a rough circle.
       e.Graphics.DrawEllipse(the_pen, 20, 20, 100, 100)
       ' Draw a smooth circle.
       e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
       e.Graphics.DrawEllipse(the_pen, 20 + 120, 20, 100, 100)
   End Using
Be aware that using the SmoothingMode.AntiAlias setting causes drawing to take slightly longer. For most applications the difference in speed is small, but the difference in quality is huge, so it's often worth using. (The Graphics object's TextRenderingHint property works similar magic when you draw text, although the default these days seems to be to use anti-aliasing so you're probably already doing that without even knowing about it.)

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date