The System.Drawing namespace includes several classes and structures. The most important of them are summarized, briefly, in Table 10-1.
Class |
Description |
---|---|
Bitmap |
Encapsulates a GDI+ bitmap, i.e., pixel data representing an image. |
Brush |
Abstract base class. Used to fill the interiors of graphical shapes. |
Brushes |
Provides static brush definitions for all standard colors. |
Color |
Structure representing colors, e.g., Color.Green. |
Font |
Defines a format for text, including font face, and sizeEncapsulates a typeface, size, style, and effects. |
FontFamily |
Group of type faces with the same basic design. |
Graphics |
Encapsulates a GDI+ drawing surface. |
Icon |
Transparent bitmaps used for Windows icons. |
Image |
Abstract base class common to the Bitmap, Icon, and Metafile classes. |
Pen |
Defines an object used to draw lines and curves. |
Pens |
Provides static Pen definitions for all the standard colors. |
Point |
Structure used to represent an ordered pair of integers. Typically used to specify two-dimensional Cartesian coordinates. |
PointF |
Same as Point, but uses a floating-point number (float in C#, Single in VB.NET) rather than an integer. |
Rectangle |
Structure that represents the location and size of a rectangular region. |
RectangleF |
Same as Rectangle, but uses floating-point values (float in C#, single in VB.NET) rather than integers. |
Size |
Structure that represents the size of a rectangular region as an order pair (Point) representing width and height. |
SizeF |
Same as Size, but uses PointF rather than Point. |
SystemBrushes |
A utility class with 21 static, read-only properties that return objects of type Brush (each of a different color). |
SystemPens |
A utility class with 15 static, read-only properties that return objects of type Pen (each of a different color). |
Arguably the most important class for graphics programming is (surprise!) the Graphics class. The other classes will be described as they are encountered, but before proceeding, let's examine the Graphics class in detail.
10.1.1 The Graphics Class
The Graphics class represents a GDI+ drawing surface. A Graphics object maintains the state of the drawing surface, including the scale and units, as well as the orientation of the drawing surface.
The Graphics class provides many properties. The most commonly used properties are listed in Table 10-2, most of which will be demonstrated later in this chapter.
Property |
Type |
Description |
---|---|---|
Clip |
Region |
Read/write. Specifies the area available for drawing. |
DpiX / DpiY |
Float / single |
Read/write. The horizontal and vertical resolution (respectively) of the Graphics object in dots per inch. |
PageScale |
Float / single |
Read/write. The scaling between world units and page units for this Graphics object. |
PageUnit |
GraphicsUnit |
Read/write. The unit of measure for page coordinates. Valid values are members of the GraphicsUnit enumeration, listed in Table 10-3. |
The PageScale sets the scaling between the world units and the page units. To understand these concepts, you must first understand coordinates.
10.1.1.1 Coordinates
The French philosopher René Descartes (1596-1650) is best known today for stating that while he may doubt, he can not doubt that he exists. This is summarized in his oft-quoted statement Cogito Ergo Sum (I think, therefore I am).[1]
[1] Philosopher joke: Rene Descartes goes into McDonald's and orders a Big Mac. The person behind the counter asks, "You want fries with that?" Descartes replies "I think not," and immediately disappears.
Among mathematicians, Descartes may be best known for inventing Analytical Geometry and what are now called Cartesian coordinates. In a classic Cartesian coordinate system, you envision an x axis and a y axis, as shown in Figure 10-1, with the origin (0,0) at the center. The values to the right of the origin and above the origin are positive, and the values to the left and below are negative.
Figure 10-1. Cartesian coordinates
In most graphical programming environments, like in Windows, the coordinate system has its origin at the upper-lefthand corner, rather than in the center, and you count upward to the right and down, as shown in Figure 10-2. The coordinates you pass to the various drawing methods of the Graphics class are called world coordinates.
Figure 10-2. World coordinates
10.1.1.2 Transforms introduced
These world coordinates are transformed into page coordinates by world transformations. You'll use these world transformations (e.g., TranslateTransform, ScaleTransform, and RotateTransform) later in this chapter to set the center and the orientation of your coordinate system. When drawing a clock face, for example, setting the origin (0,0) to the center of the clock is more convenient.
Page transforms convert page coordinates into device coordinates: pixels relative to the upper-lefthand corner of the client area on your monitor, bitmap, page, etc. The page transforms are the PageUnit and PageScale properties of the Graphics object, which were listed in Table 10-2.
The PageUnit property chooses the unit in which you will make your transformations and scale your drawings. These Units are one of the GraphicsUnits-enumerated values shown in Table 10-3.
Enumerated value |
Unit of measure |
---|---|
Display |
1/75 of an inch |
Document |
1/300 of an inch |
Inch |
1 inch |
Millimeter |
1 millimeter |
Pixel |
1 Pixel |
Point |
1/72 of an inch |
World |
World unit |
Using the unit described by the PageUnit, you can set the PageScale that specifies the value for scaling between world units and page units for the current Graphics object. You'll see this at work later in this chapter when you'll create a scale of 2000 units by 2,000 unitsthat is, rather than working in pixels or inches, you'll create an arbitrary unit that is 1/2000 of the width (or height) of your screen.
10.1.2 Graphics Methods
The Graphics class has many methods for drawing to the graphics device. They include methods that begin with Draw, shown here:
DrawArc |
DrawIcon |
DrawPath |
DrawBezier |
DrawIconUnstretched |
DrawPie |
DrawBeziers |
DrawImage |
DrawPolygon |
DrawClosedCurve |
DrawImageUnscaled |
DrawRectangle |
DrawCurve |
DrawLine |
DrawRectangles |
DrawEllipse |
DrawLines |
DrawString |
They also include methods that begin with Fill, shown here:
FillClosedCurve |
FillPie |
FillRectangles |
FillEllipse |
FillPolygon |
FillRegion |
FillPath |
FillRectangle |
(Draw methods draw the outline of the figure; Fill methods fill the interior with the color of the current brush).
The methods you'll use in this chapter, and other commonly used methods, are summarized in Table 10-4.
Method |
Description |
---|---|
Clear |
Clear the drawing area and fill it with the specified color. |
DrawString |
Draw a string at a particular location using a particular brush and font. |
DrawLine |
Draw a line connecting two points. |
FillEllipse |
Fill an ellipse defined by a bounding rectangle. |
MeasureString |
Return the size of a string when drawn with a specific font within the context of the current Graphics object. |
Restore |
Restore the state of a Graphics object (see Save, below). |
RotateTransform |
Apply a rotation to the transformation matrix of a Graphics object. |
Save |
Save the state of a Graphics object. |
ScaleTransform |
Apply a scaling operation to the transformation matrix of a Graphics object. |
TransformPoints |
Transform an array of points from one coordinate space to another, using the current world and page transformations. |
TranslateTransform |
Apply a translation operation on the transformation matrix. |
Create the second hand dot shown in Figure 10-5 using the FillElipse method, and create the clock hands using the DrawLine method. Write characters using the DrawString method. You can learn more about this process below.
Save and Restore are two important methods in the Graphics class. The Save method saves the current state of the Graphics class and returns that state in a GraphicsState object. You do not need to know anything about the internal mechanism of the GraphicsState object. It can be treated as a token that you pass into Restore, which restores the saved state of the Graphics object. Thus, you might write code that looks like this:
GraphicsState state = myGraphicsObject.Save( ); // make transformations here myGraphicsObject.Restore(state);
dim state as GraphicsState = myGraphicsObject.Save( ) '' make transformations here myGraphicsObject.Restore(state)
Using Save and Restore allows you to change the scale or orientation of your Graphics object, and then set it back to the way it was before you transformed it.
The transformation methods are detailed later in this chapter.
10.1.3 Obtaining a Graphics Object
You can obtain a Graphics object in many different ways. Two of the ways involve the Paint event, which is described in detail in the next section. You can add an event handler to the Paint event delegate or override the OnPaint event handler method. In either case, the event handler method takes a PaintEventArgs parameter, which has a property that returns a Graphics object.
protected override void OnPaint ( PaintEventArgs e ) { Graphics g = e.Graphics;
protected override sub OnPaint (e as PaintEventArgs) dim g as Graphics = e.Graphics
|
Another way to obtain a Graphics object is to call the CreateGraphics method on a control or form:
Graphics g = this.CreateGraphics( );
dim g as Graphics = me.CreateGraphics( )
|
10.1.4 Color Structure
The System.Drawing namespace provides a Color structure to represent standard system-defined colors. Whenever a color is needed, you can use any of the 141 public static properties of the Color structure. These properties include such standbys as Red, Blue, Green, Gray, and Black; variations on the standards such as LightBlue, LightGreen, LightPink, and DarkOrange; and gems such as LightGoldenRodYellow, MediumSlateBlue, and PapayaWhip. The complete list of standard colors is provided in the Appendix.
In addition to the standard colors, 26 members of the SystemColor enumeration represent the colors used for various elements of the Windows desktop. They include such items as ActiveBorder, Desktop, and WindowFrame. The complete SystemColor enumeration is also shown in the Appendix.
The combination of the standard colors and the SystemColors comprise the KnownColor enumeration.
The color system is based on the ARGB model, where A stands for Alpha, or the transparency of the color, and RGB stands for Red-Green Blue. One byte is allocated each for the Alpha and the three primary colors. An Alpha value of 0 is transparent and FF is opaque. Likewise, a zero value for a color (R, G, or B) indicates that none of that color is present, while a value of FF indicates that the color is full on.
In addition to the static properties representing the standard colors, several commonly used instance properties of the Color structure are listed in Table 10-5.
Value |
Description |
---|---|
A |
Returns byte value of Alpha component |
R |
Returns byte value of red component |
G |
Returns byte value of green component |
B |
Returns byte value of blue component |
Name |
Returns the name of the color, either user-defined, a known color, or an RGB value |
10.1.5 Geometric StructuresPoints, Rectangles, and Sizes
The System.Drawing namespace provides several structures for representing a location (Point and PointF), a rectangular area (Rectangle and RectangleF), and a size (Size and SizeF).
All of these structures consist of a pair of read/write ordered pair of numbers. The versions without the trailing F in the name take an ordered pair of ordered pairs of integers (four integers in total) and the versions with the trailing F take an ordered pair of ordered pairs of floating-point numbers (float in C# or single in VB.NET). The numbers typically represent pixels. They can also represent other units, such as Inch or Millimeter, hence the need for floating-point as well as integer values.
The integer versions of these structures can be cast to the floating-point version:
PointF ptf; Point pt = null; ptf = pt;
dim ptf as PointF dim pt as Point ptf = pt
You cannot cast in the opposite direction, since information may be lost. However, all three integer versions provide static methods (Ceiling, Round, and Truncate) for converting from the floating-point version to the integer version.
In the Point/PointF structure, the first number represents the x, or horizontal coordinate in a two-dimensional Cartesian coordinate system. The second number represents the y, or vertical coordinate.
The Size/SizeF structures are similar to the Point/PointF structures, except that the ordered pair of numbers represent the Width and Height properties of a rectangular region.
The Rectangle and RectangleF structures represent a rectangular region. Each has two constructors, listed in Table 10-6. The first constructor takes a Point (or PointF) structure and a Size (or SizeF) structure. The second constructor takes four numbers, either integers or float/singles. The first two numbers represent the x and y coordinates of the upper-left corner of the rectangle, and the second two numbers represent the width and height of the rectangle.
Rectangle |
Point, Size |
---|---|
Integer, Integer, Integer, Integer |
|
RectangleF |
PointF, SizeF |
Integer, Integer, Integer, Integer |
The Rectangle and RectangleF structures also provide several properties for either getting information about the rectangle or setting properties. These properties are listed in Table 10-7.
Property |
Type |
Description |
---|---|---|
Bottom |
Integer Float/single |
Read-only. Returns the y coordinate of the bottom edge of the rectangle. |
Height |
Integer Float/single |
Read/write. The height of the rectangle. |
IsEmpty |
Boolean |
Read-only. Returns true if all numeric properties have a value of zero. |
Left |
Integer Float/single |
Read-only. Returns the x coordinate of the left edge of the rectangle. |
Location |
Point/PointF |
Read/write. The point at the upper-left corner of the rectangle. |
Right |
Integer Float/single |
Read-only. Returns the x coordinate of the right edge of the rectangle. |
Size |
Size/SizeF |
Read/write. The size of the rectangle. |
Top |
Integer Float/single |
Read-only. Returns the y coordinate of the top edge of the rectangle. |
Width |
Integer Float/single |
Read/write. The width of the rectangle. |
X |
Integer Float/single |
Read/write. The x coordinate of the upper-left corner of the rectangle. |
Y |
Integer Float/single |
Read/write. The y coordinate of the upper-left corner of the rectangle. |
10.1.6 Brush and Brushes
A Brush object is used to fill the interior spaces of graphical shapes. The Brush class is abstract (MustInherit), and five different classes are derived from Brush, listed in Table 10-8.
Class |
Description |
---|---|
HatchBrush |
A rectangular brush with a hatch style from the HatchStyle enumeration, such as BackwardDiagonal, DarkVertical, Divot, and Percent60. The ForegroundColor property gets the color of the lines and the BackgroundColor property gets the color of the space behind the lines. |
LinearGradientBrush |
A brush with a linear gradient. Properties such as Blend, GammaCorrection, and Transform allow you to change the appearance programatically. |
PathGradientBrush |
A brush that fills a graphical shape with a gradient. Properties such as Blend, CenterColor, and Transform allow you to change the appearance programatically. |
SolidBrush |
A brush that fills a graphical shape with a color. Valid colors are members of the Color structure. |
TextureBrush |
A brush that fills a graphical shape with a texture. The texture can come from an Image object, either a bitmap or a metafile. |
For easy access to the colored brushes, a Brushes class (note the plural) contains only static (shared), read-only properties of type Brush corresponding to each standard color. This Brushes class often provides the Brush object used in calls to the DrawString method.
|
10.1.7 Pen and Pens
The Pen and Pens classes are similar to the Brush and Brushes classes, except they are used for drawing lines and curves rather than filling graphical shapes. The constructors of the Pen class take either a Brush object or a Color as an argument. Additionally, you can pass in a floating-point number (float in C#, single in VB.NET) that specifies the width of the Pen object.
As with the Brushes class, there is a Pens class (note the plural) for easy access to a Pen object of a standard color. The Pens class contains static members corresponding to each standard color. The following code snippet demonstrates one way to instantiate and use a Pen object.
Pen pn = Pens.LimeGreen; pn.EndCap = LineCap.ArrowAnchor; pn.Width = 20; g.DrawLine(pn,0,0,0,50);
Dim pn as Pen = Pens.LimeGreen pn.EndCap = LineCap.ArrowAnchor pn.Width = 20 g.DrawLine(pn, 0, 0, 0, 50)
Table 10-9 lists many of the most commonly used properties of the Pen class. Many of them will be demonstrated in the Analog Clock project later in this chapter.
Property |
Type |
Description |
---|---|---|
Alignment |
PenAlignment |
Read/write. Specifies the alignment for this Pen object relative to a theoretical line. Valid values are members of the PenAlignment enumeration, listed in Table 10-10. |
Brush |
Brush |
Read/write. The Brush object that controls attributes of the pen (e.g., does the pen draw a solid or a pattern?). |
Color |
Color |
Read/write. The color of the Pen. Legal values are members of the Color structure, e.g., Color.DarkGoldenrod. |
DashCap |
DashCap |
Read/write. The cap style used at the beginning and end of the dashes that comprise a dashed line. Valid values are Flat, Round, and Triangle. |
DashPattern |
float[ ] / single( ) |
Read/write. An array of numbers specifying the lengths of alternating dashes and spaces. |
DashStyle |
DashStyle |
Read/write. The style used for dashed lines. Valid values are members of the DashStyle enumeration, listed in Table 10-11. |
EndCap |
LineCap |
Read/write. The enumerated arrow type. Valid values are members of the LineCap enumeration, listed in Table 10-12. |
StartCap |
LineCap |
Read/write. The enumerated arrow type. Valid values are members of the LineCap enumeration, listed in Table 10-12. |
Width |
Float |
The thickness of the drawn line. |
Value |
Description |
---|---|
Center |
Centered over the theoretical line |
Inset |
Positioned to the inside of the theoretical line |
Left |
Positioned to the left of the theoretical line |
Outset |
Positioned to the outside of the theoretical line |
Right |
Positioned to the right of the theoretical line |
Value |
Description |
---|---|
Custom |
Custom style |
Dash |
Dashes |
DashDot |
Repeating pattern of dash-dot |
DashDotDot |
Repeating pattern of dash-dot-dot |
Dot |
Dots |
Solid |
Solid line |
Value |
Description |
---|---|
AnchorMask |
Mask to check if cap is an anchor cap |
ArrowAnchor |
Arrow-shaped anchor cap |
Custom |
Custom line cap |
DiamondAnchor |
Diamond-shaped anchor cap |
Flat |
Flat line cap |
NoAnchor |
No anchor |
Round |
Round line cap |
RoundAnchor |
Round anchor cap |
Square |
Square cap |
SquareAnchor |
Square anchor cap |
Triangle |
Triangular line cap |
10.1.8 Paint Event
All controls have a Paint event, which is raised when the control is about to be drawn. You can add an event handler to the Paint event delegate to dictate how the control is drawn. Using the Paint event, for example, you can draw a string of text directly onto the client area of a form, as shown in Example 10-1 (in C#) and in Example 10-2 (in VB.NET).
|
Example 10-1. Drawing a string with Paint event using C# (PaintDemo.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class PaintDemo : Form { public PaintDemo( ) { Text = "Paint Demonstration"; Size = new Size(300,200); Paint += new PaintEventHandler(PaintHandler); } static void Main( ) { Application.Run(new PaintDemo( )); } private void PaintHandler(object sender, PaintEventArgs e) { Graphics g = e.Graphics; g.DrawString("Look Ma, no label!", Font, Brushes.Black, 50, 75); } } }
Example 10-2. Drawing a string with Paint event using VB.NET (PaintDemo.vb)
imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class PaintDemo : inherits Form public sub New( ) Text = "Paint Demonstration" Size = new Size(300,200) AddHandler Paint, AddressOf PaintHandler end sub public shared sub Main( ) Application.Run(new PaintDemo( )) end sub private sub PaintHandler(ByVal sender as object, _ ByVal e as PaintEventArgs) dim g as Graphics = e.Graphics g.DrawString("Look Ma, no label!", Font, Brushes.Black, 50, 75) end sub end class end namespace
When either program in Example 10-1 or Example 10-2 is compiled and run, you will get the form shown in Figure 10-3.
Figure 10-3. Paint event demonstration
Both versions of the PaintDemo program start by referencing the required namespaces: System, System.Drawing, and System.Windows.Forms. Inside the constructor of each program, the Text and Size properties are set, and the PaintHandler method is added to the delegate for the Paint event:
Text = "Paint Demonstration"; Size = new Size(300,200); Paint += new PaintEventHandler(PaintHandler);
Text = "Paint Demonstration" Size = new Size(300,200) AddHandler Paint, AddressOf PaintHandler
Remember that all of these properties (and events) are implicitly members of the classi.e., the PaintDemo form. You can make this explicit by using the appropriate lines of code:
this.Text = "Paint Demonstration"; this.Size = new Size(300,200); this.Paint += new PaintEventHandler(PaintHandler);
Me.Text = "Paint Demonstration" Me.Size = new Size(300,200) Me.AddHandler Paint, AddressOf PaintHandler
The PaintHandler method is a typical event handler, taking two arguments. The first is of type object and the second is of type PaintEventArgs, which has the two read-only properties listed in Table 10-13.
Property |
Type |
Description |
---|---|---|
ClipRectangle |
Rectangle |
The rectangle to paint |
Graphics |
Graphics |
The Graphics object used to paint |
A new Graphics object is instantiated from the PaintEventArgs argument.
Graphics g = e.Graphics;
dim g as Graphics = e.Graphics
Then the DrawString method is invoked to render the desired text string on the form client area. The DrawString method has several overloaded versions, but all of them take at least the string to draw, the font to use, the brush to use (which controls the color and appearance of the characters), and a location:
g.DrawString("Look Ma, no label!", Font, Brushes.Black, 50, 75);
g.DrawString("Look Ma, no label!", Font, Brushes.Black, 50, 75)
In this example, the font used is the current font for the form (it also could have been written as this.Font in C# or me.Font in VB.NET), the brush is Black, and the location of the upper-left corner of the text string is 50 units in from the left edge of the client area and 75 units down from the top.
10.1.8.1 Overriding the OnPaint method
The programs shown in Example 10-1 and Example 10-2 worked by adding an event handler method to the Paint event. You can accomplish the same outcome by overriding the OnPaint event directly just as you might override any virtual method. The Control class defines the OnPaint method as follows:
protected virtual void OnPaint( PaintEventArgs e );
Overridable Protected Sub OnPaint( ByVal e As PaintEventArgs )
Example 10-3 (in C#) and in Example 10-4 (in VB.NET) demonstrate how to override the OnPaint event. The differences from the previous examples are highlighted.
Example 10-3. Overriding the OnPaint event in C# (PaintOverride.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class PaintOverride : Form { public PaintOverride( ) { Text = "Paint Demonstration"; Size = new Size(300,200); } static void Main( ) { Application.Run(new PaintOverride( )); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.DrawString("Look Ma, I'm overridden!", Font, Brushes.Black, 50, 75); base.OnPaint(e); } } }
Example 10-4. Overriding the OnPaint event in VB.NET (PaintOverride.vb)
imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class PaintOverride : inherits Form public sub New( ) Text = "Paint Demonstration" Size = new Size(300,200) end sub public shared sub Main( ) Application.Run(new PaintOverride( )) end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim g as Graphics = e.Graphics g.DrawString("Look Ma, I'm overridden!", _ Font, Brushes.Black, 50, 75) end sub end class end namespace
In Example 10-3 and Example 10-4, no methods are added to any event delegates. Instead, the protected OnPaint method is overridden. When overriding an event handler, the only required argument is the event argumentin this case, PaintEventArgs.
The last line in the overridden method chains up to the base method (invokes the base method) to ensure that all the base class functionality will be implemented and that any other methods registered with the delegate will be notified. This is done with the line:
base.OnPaint(e);
myBase.OnPaint(e)
The remaining two lines in the overridden method are the same as in the previous examples.
10.1.8.2 Forcing a paint eventthe Invalidate method
You can force a region to redraw by calling the Invalidate method on a control. This method does not actually raise the Paint event, but invalidates the area of the control or a region within the control. Once an area or region has been invalidated, it will be redrawn. This will occur when all current events are finished processing. If you want the redraw to occur immediately, call the Update method after calling the Invalidate method.
The Invalidate method is overloaded with six different versions. The parameters supplied to the method dictate exactly what part of the control will be invalidated. The overloaded versions are listed in Table 10-14.
Method Call |
Description |
---|---|
Invalidate( ) |
Invalidates the region of the control |
Invalidate(Boolean) |
If Boolean is true, invalidates the child controls |
Invalidate(Rectangle) |
Invalidates the region specified by the Rectangle |
Invalidate(Region) |
Invalidates the specified Region |
Invalidate(Rectangle, Boolean) |
Invalidates the region specified by the Rectangle, and if Boolean is true, invalidates the child controls |
Invalidate(Region, Boolean) |
Invalidates the specified Region, and if Boolean is true, invalidates the child controls |
Use of the Invalidate method is shown in Example 10-5 (in C#) and in Example 10-6 (in VB.NET). The lines of code differing from the basic examples in Example 10-1 and Example 10-2 are highlighted.
Example 10-5. Invalidate method in C# (PaintInvalidate.cs)
using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class PaintInvalidate : Form { private Button btn; public PaintInvalidate( ) { Text = "Paint Invalidate Demonstration"; Size = new Size(300,200); btn = new Button( ); btn.Parent = this; btn.Location = new Point(25,25); btn.Text = "Update"; btn.Click += new System.EventHandler(btn_Click); } static void Main( ) { Application.Run(new PaintInvalidate( )); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; String str = "Look Ma, I'm overridden!"; str += " The time is " + DateTime.Now.ToLongTimeString( ); g.DrawString(str, Font, Brushes.Black, 50, 75); } private void btn_Click(object sender, EventArgs e) { Invalidate( ); } } }
Example 10-6. Invalidate method in VB.NET (PaintInvalidate.vb)
imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class PaintInvalidate : inherits Form private WithEvents btn as Button public sub New( ) Text = "Paint Invalidate Demonstration" Size = new Size(300,200) btn = new Button( ) btn.Parent = me btn.Location = new Point(25,25) btn.Text = "Update" end sub public shared sub Main( ) Application.Run(new PaintInvalidate( )) end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim g as Graphics = e.Graphics dim str as string = "Look Ma, I'm overridden!" str += vbCrLf + "The time is " + DateTime.Now.ToLongTimeString( ) g.DrawString(str, Font, Brushes.Black, 50, 75) end sub private sub btn_Click(ByVal sender as object, _ ByVal e as EventArgs) _ Handles btn.Click Invalidate( ) end sub end class end namespace
When either program is compiled and run, you get something similar to that shown in Figure 10-4. Clicking on the button updates the time displayed in the client area of the form.
Figure 10-4. Paint Invalidate program
The Invalidate method is called against the Form object. The line:
Invalidate( )
is implicitly the same as:
this.Invalidate( );
me.Invalidate( )
Another way to force a Form to invalidate itself and cause the Paint event to be raised is to set the ResizeRedraw property to true. This will cause the object, the Form in this case, to redraw itself every time the object is resized. In fact, if an application is not behaving the way you might expect when resizing, then setting this property to true might alleviate the problem.
Windows Forms and the .NET Framework
Getting Started
Visual Studio .NET
Events
Windows Forms
Dialog Boxes
Controls: The Base Class
Mouse Interaction
Text and Fonts
Drawing and GDI+
Labels and Buttons
Text Controls
Other Basic Controls
TreeView and ListView
List Controls
Date and Time Controls
Custom Controls
Menus and Bars
ADO.NET
Updating ADO.NET
Exceptions and Debugging
Configuration and Deployment