Creating Your Own Graphics Objects


In this section, you'll learn how to use some of the graphics primitives provided by Visual Basic .NET to draw your own graphics objects. Rather than just read about graphics objects, you will build a simple gauge control by using Visual Basic .NET's Graphics objects. You will develop the Gauge control by using the techniques you learned in Chapter 21. When you are finished, you will have a new control that you can use in other projects.

You should start by creating a new project and then selecting the Add User Control menu option. You should name the new control Gauge . The following section shows you how to start adding the code to the Gauge control.

The Gauge Control Code

Listing 22.3 shows the members of the Gauge control class.

Listing 22.3 The Data Members for the Gauge Control
 Imports System.ComponentModel Public Class Gauge  Inherits System.Windows.Forms.UserControl  ' Windows Form Designer generated code  '================== Data Members =====================  Private mMin As Double     'Minimum gauge value  Private mMax As Double     'Maximum gauge value  Private mDanger As Double    'Redline danger value  Private mCaution As Double   'Yellowline cautionary value  Private mRange As Double    'The range of gauge values  Private mCurrent As Double   'Current gauge value  Private mTick As Double     'A tick mark on the scale  Private mGap As Integer     'The range between tick marks  Private mTall As Integer    'How tall is the gauge  Private mWide As Integer    'How wide is the gauge  Private mLeftSide As Integer  'Where is the left side of the gauge  Private mTopSide As Integer   'Where is the top of the gauge 

Listing 22.3 begins by importing System.ComponentModel so you can classify each member and display a help message in the Properties window.

The purpose of each data member of the Gauge control is fairly clear from their names and comments in Listing 22.3. There are, however, two members that may be hard to figure out. The mDanger member allows the user to specify a value at which the color of the gauge changes to red. The mCaution member allows the user to set a value that causes the gauge to display yellow. Together, these two members allow the user to create the effect of redline and yellowline values for the gauge.

The mRange member is the range of values that should be displayed on the gauge. This is set by subtracting mMin from mMax . mTick is set by dividing mRange by 5 and is used for placing the scale values on the gauge. (To simplify things a bit, the number of scale values displayed is limited to five.) The remaining members are used to actually draw the control.

Listing 22.4 shows the property methods for the Gauge control.

Listing 22.4 The Gauge Control Property Methods
 '================== The Property Procedures ===================== <Description("The minimum gauge value"), _ Category("Appearance")> _ Property Minimum() As Double  ' Minimum  Get   Return mMin  End Get  Set(ByVal Value As Double)   mMin = Value  End Set End Property <Description("The maximum gauge value"), _ Category("Appearance")> _ Property Maximum() As Double   ' Maximum  Get   Return mMax  End Get  Set(ByVal Value As Double)   mMax = Value  End Set End Property <Description("The gauge danger value where the color changes to red"), _ Category("Appearance")> _ Property Danger() As Double    ' The redline danger value  Get   Return mDanger  End Get  Set(ByVal Value As Double)   mDanger = Value  End Set End Property <Description("The gauge caution value where the color changes to yellow"),_ Category("Appearance")> _ Property Caution() As Double   ' The yellowline cautionary value  Get   Return mCaution  End Get  Set(ByVal Value As Double)   mCaution = Value  End Set End Property <Description("The gauge height"), _ Category("Appearance")> _ Property Tall() As Integer     ' How tall is the gauge?  Get   Return mTall  End Get  Set(ByVal Value As Integer)   mTall = Value  End Set End Property <Description("The gauge width"), _ Category("Appearance")> _ Property Wide() As Integer     ' How wide is the gauge?  Get   Return mWide  End Get  Set(ByVal Value As Integer)   mWide = Value  End Set End Property <Description("The left edge location of the gauge"), _ Category("Appearance")> _ Property LeftSide() As Integer    ' Where's the left side of the gauge  Get                 ' on the form?   Return mLeftSide  End Get  Set(ByVal Value As Integer)   mLeftSide = Value  End Set End Property <Description("The top edge location of the gauge"), _ Category("Appearance")> _ Property TopSide() As Integer    ' Where is the top of the gauge on  Get                ' the form?   Return mTopSide  End Get  Set(ByVal Value As Integer)   mTopSide = Value  End Set End Property <Description("The present value of the gauge"), _ Category("Data")> _ Property Current() As Double    ' What is current value?  Get   Return mCurrent  End Get  Set(ByVal Value As Double)   mCurrent = Value  End Set End Property 

The code in Listing 22.4 is very straightforward. Each property method simply gets or sets the appropriate value for the data member of the control. The real work for the control is done in the remaining methods. The SetGaugeParameters() and Gauge_Resize() methods are shown in Listing 22.5.

Listing 22.5 The SetGaugeParameters() and Gauge_Resize() Methods
 '==================== Methods ======================== Private Sub SetGaugeParameters()  ' Purpose: This subroutine sets some of the parameters that are  '      used by the gauge.  '  ' Argument list:  '  none  '  ' Return value:  '  n/a  '  If mCurrent > mMax Then     ' Value too large?   mCurrent = mMax  End If  If mCurrent < mMin Then    ' Value too small?   mCurrent = mMin  End If  mRange = mMax - mMin      ' Find the gauge range of values  mTick = mRange / 5.0      ' Find where tick marks should start  mGap = mTall / 5        ' Find the gaps between tick marks End Sub Private Sub Gauge_Resize(ByVal sender As Object, ByVal e As _       System.EventArgs) Handles MyBase.Resize  Dim ControlWidth As Integer = Me.ClientRectangle.Width  Dim ControlHeight As Integer = Me.ClientRectangle.Height  If ControlHeight < 50 Then    ' Set a minimum control height   ControlHeight = 50   Me.Height = 50  End If  If ControlWidth < 50 Then     ' Set a minimum control width   ControlWidth = 50   Me.Width = ControlWidth  End If  mTall = Me.Height * 0.9  mTopSide = (Me.Height - mTall) / 2 ' location for top edge of gauge  mLeftSide = Me.Width * 0.05     ' Location for left edge of the gauge  mWide = Me.Width * 0.2       ' The width of the gauge  Invalidate() End Sub 

The SetGaugeParameters() method is called to check and set some of the member values for the gauge. For example, if the current value for the gauge ( mCurrent ) is greater than mMax , mCurrent is set to mMax . Likewise, if the current value is too small, mCurrent is set to mMin . After the current value is checked, the mRange , mTick , and mGap values are determined.

Control Resizing

You want the user to be able to resize the control, and the Gauge_Resize() method handles the Resize() event. Note that resizing is done relative to the control's size, not the size of the gauge. Because you want the gauge to be sized relative to the control's size, all your calculations for the gauge are based on the control size. Therefore, as the user resizes the control, the gauge should increase or decrease in size relative to the changes in the control's size.

This statement is used to determine the current width of the control:

 Dim ControlWidth As Integer = Me.ClientRectangle.Width 

Me , of course, refers to the Gauge control. The ClientRectangle method can be used to examine a list of parameters associated with the rectangle formed by the control. This statement returns the current width of the control. Your code examines only the width and height of the control, but the ClientRectangle method can be used to return additional information about the rectangle, including Top , Bottom , Left , Location , X , and Y values.

After you have determined the current size of the control, you should check to make sure the user is not trying to make the control too small. In this case, "too small" would be a control size that would not allow the gauge and its values to be displayed. You have hard-coded the minimum width and height to be 50 pixels. This value results in a fairly skinny gauge.

Programmer's Tip

graphics/tip_icon.gif

If you need a thinner gauge than shown here, you can change the 50-pixel cutoff to some smaller value. However, doing so clips the scale values that are printed on the control. Therefore, if your version allows the control to assume such small values, you might want to add code to suppress writing the scale values on the control.


These statements set the properties for the new gauge size relative to the new size of the control:

 mTall = Me.Height * 0.9  mTopSide = (Me.Height - mTall) / 2 ' location for top edge of gauge mLeftSide = Me.Width * 0.05     ' Location for left edge of the gauge mWide = Me.Width * 0.2       ' The width of the gauge 

mTall sets the height of the gauge to be 90% of the height of the control. The next calculation sets the top of the gauge ( mTopSide ) so that the gauge is centered within the control's vertical size. The third statement places the left edge of the gauge ( mLeftSide ) so that it is located near the left edge of the control. (Its value is 5% of the control's width.) Finally, the width of the gauge ( mWide ) is set to be 20% of the control's width.

You can change the gauge parameters to suit your own needs. Indeed, you could even make the hard-coded parameters (for example, .90, .05,.20) members of the class and allow the user to set those, too. Although it would take a little more work, you could also orient the gauge to make it horizontal rather than vertical. (Trying to make these changes to the code would be a valuable learning experience!)

After the members have been reset to reflect the control's new size, the code calls the Invalidate() method. The Invalidate() method call causes Visual Basic .NET to send a message to Windows to redraw the control. Upon return from the call, the control is displayed to the user, using the resized parameters.

The OnPaint() Method

The real work for the gauge is done by the Graphics object's OnPaint() method. This method is designed to paint a Visual Basic .NET Graphics object. Each Graphics object has numerous methods associated with it, and these methods are responsible for all visual aspects of the object. These responsibilities include changing colors, drawing lines and shapes, filling shapes , drawing fonts, and taking care of other visual elements that appear onscreen. Indeed, every form you've used thus far has an OnPaint() method provided by the System.Windows.Forms.Form class.

Because it is possible to override the OnPaint() method, you can write your own version of the method and use it to draw the gauge. The argument to the OnPaint() method is PaintEventArgs , which contains a Graphics property that you can use for drawing purposes. The code for the OnPaint() method is shown in Listing 22.6.

Listing 22.6 The OnPaint() Method for the Gauge Control
 Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)  ' Purpose: This subroutine overrides the OnPaint() event to draw  '      the gauge  '  ' Argument list:  '  e       the paint event arguments  '  ' Return value:  '  n/a  '  ' CAUTION: As written, this code assumes there are valid values  '      for mTop, mLeftSide, mTall, and mWide. No checks are  '      performed.  Dim Canvas As Graphics = e.Graphics  Dim MyPen As Pen = New Pen(Color.Black)  Dim MyBrush As SolidBrush = New SolidBrush(Color.Green)  Dim MyStyle As FontStyle = FontStyle.Regular  Dim MyFont As Font = New Font("Microsoft Sans Serif", 8, MyStyle)  Dim NumberOffset As Integer, buff As String  Dim TickOffset As Integer, TopOffset As Integer, TickValues As Double  Dim i As Integer  SetGaugeParameters()         ' Calculate some initial values  If mCaution <> 0 Or mDanger <> 0 Then ' have they set yellow or red lines?   If mCurrent >= mCaution Then    ' See if value requires a color change    MyBrush.Color = Color.Yellow   End If   If mCurrent >= mDanger Then    MyBrush.Color = Color.Red   End If  End If  ' Draw a rectangle and then fill it with a background color  Canvas.DrawRectangle(MyPen, mLeftSide, mTopSide, mWide, mTall)  Canvas.FillRectangle(MyBrush, mLeftSide + 1, mTopSide + 1, mWide - 1, mTall - 1)  MyBrush.Color = Color.Black      ' Reset brush color for numbers  TickOffset = mWide + mLeftSide  TickValues = mMax  NumberOffset = MyFont.GetHeight(Canvas) / 2  For i = 0 To 4            ' Draw the tick marks and values   TopOffset = mTopSide + i * mGap   ' First, draw tick marks   Canvas.DrawLine(MyPen, TickOffset, TopOffset, TickOffset + 3, TopOffset)   buff = Format(TickValues - mTick * i, ".00")  ' Now draw scale values   Canvas.DrawString(buff, MyFont, MyBrush, TickOffset + 5, _             TopOffset - NumberOffset)  Next i  ' Need this because of possible rounding errors for pixel values when drawing  ' the minimum value tick mark. It draws the minimum tick and value  Canvas.DrawLine(MyPen, TickOffset, mTopSide + mTall, TickOffset + 3, _           mTopSide + mTall)  Canvas.DrawString(CStr(mMin), MyFont, MyBrush, TickOffset + 5, _           mTopSide + mTall - NumberOffset)  ' Now draw a filled rectangle for the UNUSED portion of the gauge  ' using a white brush  MyBrush.Color = Color.White  ' This determines how "deep" to draw the new rectangle. The adjustments  ' by +/- 1 pixel is so we don't overwrite the gauge border  i = (1.0 - mCurrent / mRange) * mTall + (mMin / mRange) * mTall - 1  Canvas.FillRectangle(MyBrush, mLeftSide + 1, mTopSide + 1, mWide - 1, i) End Sub 

The OnPaint() method must use the Overrides keyword because you want to override the base class OnPaint() method. You use the PaintEventArgs parameter e to define a Graphics object named Canvas that paints the object. (The Graphics class has a number of public methods that are associated with it and that are used in this example.) The following statement defines the Graphics object:

 Dim Canvas As Graphics = e.Graphics 

The variable name Canvas reinforces the idea that you are interacting with a drawing object (that is, the surface of the control) when you use an object of the Graphics class.

The next two statements define a Pen object and a SolidBrush object:

 Dim MyPen As Pen = New Pen(Color.Black)  Dim MyBrush As SolidBrush = New SolidBrush(Color.Green) 

A Pen object is used to draw lines on a Graphics object. The SolidBrush object is derived from the Brush class and is used to draw solid shapes on the Graphics object. The Pen object draws the gauge, its tick marks, and its text. The SolidBrush object fills in the gauge with the different colors.

Visual Basic .NET provides a much larger selection of predefined color names than found in earlier releases of Visual Basic. When you write code to set the color for the Pen object or the SolidBrush object, Visual Basic .NET presents you with a list of these predefined colors, as shown in Figure 22.7. Visual Basic .NET provides about 150 colors from which to choose.

Figure 22.7. The predefined Visual Basic .NET colors.

graphics/22fig07.jpg

Colors values can now be defined differently than they were in earlier versions of Visual Basic. Previously, a function named RGB() allowed you to set the red, green, and blue (RGB) components of a color. Each color had a numeric value that varied between (the absence of the color) and 255 (full intensity of the color). By mixing these color values, you could create different color values.

A fourth color argument, named Alpha , has been added in Visual Basic .NET. The Alpha component determines the opacity of the color and can assume the values through 255 . If the Alpha value is near , the background color bleeds through the RGB components to create a transparency effect. As the Alpha value increases , the RGB colors become more "solid," and the transparency effect diminishes. For example, this statement sets the Alpha value to , the red component to 255 , and the green and blue values to :

 MyColor = Color.FromArgb(0, 255, 0, 0) 

Because the Alpha value is , the background color dominates and the red color is totally absent. If you raise the Alpha value to 50 , the background color recedes, and the red component increases, yielding a pinkish color. You can achieve some interesting color effects by using the Alpha component, especially when overlapping colors are involved.



Visual Basic .NET. Primer Plus
Visual Basic .NET Primer Plus
ISBN: 0672324857
EAN: 2147483647
Year: 2003
Pages: 238
Authors: Jack Purdum

Similar book on Amazon

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