Create a Windows form by using the Windows Forms Designer:
Build graphical interface elements by using the System.Drawing namespace.
The FCLs provide an advanced implementation of the Windows Graphics Design Interface (also known as GDI+). The GDI+ classes can be used to perform a variety of graphics-related tasks such as working with text, fonts, lines, shapes, and images. One of the main benefits of using GDI+ is that it allows you to work with Graphics objects without worrying about the specific details of the underlying platform. The GDI+ classes are distributed among four namespaces:
System.Drawing
System.Drawing.Drawing2D
System.Drawing.Imaging
System.Drawing.Text
All these classes reside in a file named System.Drawing.dll.
The Graphics class is one of the most important classes in the System.Drawing namespace. It provides methods for doing various kinds of graphics manipulations. The Graphics class is a sealed class and cannot be further inherited (unlike the Form class, for example). The only way you can work with the Graphics class is through its instances (that is, Graphics objects). A Graphics object is a GDI+ drawing surface that you can manipulate by using the methods of the Graphics class.
When you look in the documentation of the Graphics class, you see that there is no constructor available for this class, and hence a Graphics object cannot be directly created. Despite this, there are at least four ways you can get a Graphics object:
Through the Graphics property of the PaintEventArgs argument passed to the Paint event handler of a control or a form. The Graphics object thus received represents the drawing surface of the object that was the source of the event.
By calling the CreateGraphics() method of a control or form.
By calling the Graphics.FromHwnd() method and passing it the handle of the current form.
By calling the static Graphics.FromImage() method. This method takes an image object and returns a Graphics object that corresponds to that image. You can then use this Graphics object to manipulate the image.
When you have a Graphics object available, you have access to a drawing surface. You can use this surface to draw lines, text, curves, shapes, and so on. But before you can draw, you must understand the Windows forms coordinate system, which is discussed in the following section.
The Windows Forms library treats a Windows form as an object that has a two-dimensional coordinate system, as shown in Figure 1.19. Therefore, when you write text on the form or put controls on the form, the position is identified by a set of points. A point is a pair of numbers that is generally represented as (x, y) where x and y, respectively, denote horizontal and vertical distance from the origin of the form. The origin of the form is the top-left corner of the client area of the form. (The client area is the inner area of the form that you get after excluding the space occupied by title bar, sizing borders, and menu, if any.) The point of the origin is treated as (0, 0). The value of x increases to the right of the point of origin, and the value of y increases below the point of origin.
Two structures are available to represent points in a program—Point and PointF. These structures each represent an ordered pair of values (x and y). Point stores a pair of int values, whereas PointF stores a pair of float values. In addition to these values, these structures also provide a set of static methods and operators to perform basic operation on points.
Table 1.8 summarizes all the structures defined in the System.Drawing namespace.
The Graphics class provides a DrawString() method that can be invoked on a Graphics object to render a text string on the drawing surface. There are six different forms in which the DrawString() method can be used. In this section, I discuss three of them; the other three forms are the same, but with one extra argument of StringFormat type that specifies alignment and line spacing information.
STEP BY STEP1.13 Drawing Text on a Form
|
In Step by Step 1.13, why did I choose to write the code within an event handler? There are two reasons, the foremost being that the Paint event handler provides access to the Graphics object. Second, the Paint event is fired whenever the form is redrawn, which includes when the form is first shown and when the form is restored from its minimized state, as well as when the form is shown after a window overlapping it is removed. Therefore, a Paint event handler is an appropriate place to put the code that you want to be executed whenever a form is redrawn.
The code gets the Graphics object through the Graphics property of the PaintEventArgs argument of the Paint event handler. The next step is to call the DrawString() method to draw text on the form. The DrawString() method used in Step by Step 1.13 takes five arguments and has the following signature:
public void DrawString( string, Font, Brush, float, float);
The first argument, string, is the string to be displayed. I use the String.Format() method to format the string.
The second argument, Font, is the font of the string. In Step by Step 1.13 I chose to display the string by using the default font of the current form through the Font property.
The third parameter, Brush, is the type of brush. The Brushes enumeration provides a variety of Brush objects, each with a distinct color. I chose the Brushes.Black value to draw text in black.
The fourth and fifth properties, float and float, specify the x and y locations for the point that marks the start of the string on the form. Both of these values are required to be of float type. The 0 value that the code contains is implicitly converted to a float value.
EXAM TIP
Unicode Support and DrawString GDI+ and hence the Windows Forms library have full support for Unicode. This means that you can draw text in any language supported by the operating system.
You might have noticed that when you resize the form in Step by Step 1.13, the Paint event is not triggered. An obvious idea for improving this form is to have it dynamically reflect the size of the form as you resize it. What event should you handle to do that? The Resize event. Step by Step 1.14 explains how to do this.
STEP BY STEP1.14 Using the Invalidate() Method
|
After you complete Step by Step 1.14, the program works as desired. What's the deal with the Invalidate() method? The Invalidate() method causes the paint message to be sent to the form.
As a result, the Paint event handler is called. So this handy method can be called whenever the code in the Paint event handler needs to be executed. In Step by Step 1.14, the code makes a call to the Invalidate() method whenever the form is resized. The Invalidate() method is available in various forms, and you can refresh a specific portion of a form by using one of these forms.
EXAM TIP
Invalidate() Method Calls When you call the Invalidate() method without any parameters, the Paint event is called for the entire area. If only a particular portion of the control needs to be refreshed, then calling Invalidate() for the entire area is rather taxing on application performance. In such a case you should call Invalidate() with a Rectangle parameter that specifies the portion of the control that you are interested in refreshing.
Given the frequent requirement of calling Paint whenever Resize is fired, the Windows Forms library designers created a useful property: ResizeRedraw. This is a protected property that the Form class inherits from the Control class. When ResizeRedraw is set to true, it instructs a control (or a form, in this case) to redraw itself when it is resized. Its default value is false. Step by Step 1.15 shows how to use ResizeRedraw.
STEP BY STEP1.15 Using the ResizeRedraw Property
|
The form's constructor is a good place to set the ResizeRedraw property. You could alternatively write it inside the Main() method itself.
As one more enhancement to Step by Step 1.15, you can center the text programmatically within the form. To do so, first you need to find the coordinates of the center of the form. You can find the horizontal distance by dividing the width of the client area (ClientSize.Width) by 2, and you can find the vertical distance by dividing the height of the client area (ClientSize.Height) by 2. The ClientSize properties give you access to a Size structure that represents the size of the client area of the form. But this does not really center the text onscreen because it simply causes the text to start from the center, and depending on how long it is, it might appear toward the right of the center. You need to adjust the coordinates of the center point according to the size of the string. Keep in mind that the size of the string can vary depending on what font you use for the text. A safe way to determine string size is to use the MeasureString() method of the Graphics object, as shown in the following code segment:
SizeF stringSize = grfx.MeasureString(str, Font);
You can then calculate the modified coordinates for placing the string as x = (ClientSize.Width–stringSize.Width)/2 and y = (ClientSize.Height–stringSize.Height)/2.
There is an alternative approach, however. You can use the StringFormat object in the following signature of the DrawString() method:
public void DrawString( string, Font, Brush, PointF, StringFormat);
The StringFormat argument lets you specify the text alignment and spacing options for the text. Step by Step 1.16 uses this form of DrawString() to center text onscreen.
The code begins by calculating the center coordinates of the form. When you have the coordinates of the center, you want the string to be horizontally centered at that point. Calling StringAlignment.Center does this job. StringAlignment is an enumeration that is available in the System.Drawing namespace that specifies the location of the alignment of the text.
By default, when the DrawString() method draws a string, it aligns the top of the string with its x-coordinate value. This does not make much difference if the height of the text itself is not great, but as you increase the size of the font, text begins to hang down, starting from the x-axis. To center the text vertically within its own line, you can set the LineAlignment property of the StringFormat object to StringAlignment.Center.
Note the use of Font and Brush objects in Step by Step 1.16. The code creates a new Font object and specifies a font name and size. I recommend that you change its value and experiment with it. Rather than use the brush specified by the Brushes.Black value, the code in Step by Step 1.16 creates a Brush object that takes the value of its color from the current form's ForeColor property. If you change the ForeColor property of the form by using the Properties window, the change is automatically reflected here. Using a brush based on the ForeColor property of the form is a good idea as compared to using an absolute value such as Brushes.Black for a brush. For example, if the form designer has set the BackColor property of the form to black and the ForeColor property to white, text drawn using Brushes.Black would not be visible, but the brush made from the ForeColor property would be visible.
The Graphics class allows you to draw various graphical shapes such as arcs, curves, pies, ellipses, rectangles, images, paths, and polygons. Table 1.9 lists some important drawing methods of the Graphics class.
Method | Description |
---|---|
DrawArc() | Draws an arc that represents a portion of an ellipse |
DrawBezier() | Draws a Bézier curve defined by four points |
DrawBeziers() | Draws a series of Bézier curves |
DrawClosedCurve() | Draws a closed curve defined by an array of points |
DrawCurve() | Draws a curve defined by an array of points |
DrawEllipse() | Draws an ellipse defined by a bounding rectangle specified by a pair of coordinates, a height, and a width |
DrawIcon() | Draws the image represented by the specified Icon object at the given coordinates |
DrawImage() | Draws an Image object at the specified location, preserving its original size |
DrawLine() | Draws a line that connects the two points |
DrawLines() | Draws a series of line segments that connect an array of points |
DrawPath() | Draws a GraphicsPath object |
DrawPie() | Draws a pie shape defined by an ellipse and two radial lines |
DrawPolygon() | Draws a polygon defined by an array of points |
DrawRectangle() | Draws a rectangle specified by a point, a width, and a height |
DrawRectangles() | Draws a series of rectangles |
DrawString() | Draws the given text string at the specified location, with the specified Brush and Font objects |
In Step by Step 1.17 you use some of the methods shown in Table 1.9 to draw shapes on a form's surface.
STEP BY STEP1.17 Using the Draw Methods of the Graphics Class
|
The Draw methods used in Step by Step 1.17 take five arguments:
The first argument of each method is the Pen object that is used to draw the shape. There are several ways you can create a Pen object. The simplest way is to use a readymade Pen object from the Pens class. Or you can create a Pen object by using the Pen class constructor. Table 1.10 lists the different pen-related classes that are available in the System.Drawing namespace.
The second and third arguments are the x- and y-coordinates of the upper-left corner where the desired shape is to be drawn.
The fourth and fifth parameters indicate the width and height of the desired shape to be drawn. In the case of DrawLine, these indicate the x- and y-coordinates of the ending point of the line drawn.
Class | Description |
---|---|
Pen | Defines an object used to draw lines and curves. |
Pens | Provides 140 static properties, each representing a pen of a color supported by Windows Forms. |
SystemPens | Provides a set of static properties, each named after a Windows display element such as ActiveCaption, WindowText, and so on. Each of these properties returns a Pen object with a width of 1. |
The reason you must include a reference to the System.Drawing.Drawing2D namespace in the program shown in Step by Step 1.17 is that you are using an enumeration named SmoothingMode. This enumeration class is defined in the namespace System.Drawing.Drawing2D, so a reference to the namespace must be present in the program if the C# compiler is to uniquely identify it.
The Graphics object has a property named SmoothingMode that can take the values of the SmoothingMode enumeration type. Table 1.11 summarizes these values. The SmoothingMode property specifies the quality of rendering. The Windows Forms library supports antialiasing, which produces text and graphics that appear to be smooth.
NOTE
Antialiasing Antialiasing is a technique for rendering images where partially transparent pixels are drawn close to the opaque pixels present at the edges of a drawing. This actually makes the edges kind of fuzzy, but this effect makes the edges appear smoother to human eyes than the original form. Because there are extra efforts involved in antialiasing, it makes rendering of graphics slower than not using antialiasing.
Member Name | Description |
---|---|
AntiAlias | Specifies an antialiased rendering. |
Default | Specifies no antialiasing. Same as None. |
HighQuality | Specifies a high-quality, low-performance rendering. Same as AntiAlias. |
HighSpeed | Specifies a high-performance, low-quality rendering. Same as None. |
Invalid | Specifies an invalid mode, raises an exception. |
None | Specifies no antialiasing. |
In addition to the Draw methods, the Graphics class also provides a variety of Fill methods (see Table 1.12). You can use these methods to draw a solid shape on a form.
Method Name | Description |
---|---|
FillClosedCurve() | Fills the interior of a closed curve defined by an array of points |
FillEllipse() | Fills the interior of an ellipse defined by a bounding rectangle |
FillPath() | Fills the interior of a GraphicsPath object |
FillPie() | Fills the interior of a pie section defined by an ellipse and two radial lines |
FillPolygon() | Fills the interior of a polygon defined by an array of points |
FillRectangle() | Fills the interior of a rectangle specified by a point, a width, and a height |
FillRectangles() | Fills the interiors of a series of rectangles |
FillRegion() | Fills the interior of a Region object |
STEP BY STEP1.18 Using the Fill Methods of the Graphics Class
|
The syntax of the Fill methods is somewhat similar to that of corresponding Draw methods. The only difference is that the Fill methods use a Brush object to fill a drawing object with a color.
Creating the yellow brush in Step by Step 1.18 looks interesting. While creating this color, you do an “alpha-blending” with the yellow color, to get a kind of transparent yellow color that is used to produce an overlay effect.
You use a SolidBrush object in Step by Step 1.18 to fill shapes. Other types of brushes can be used to create fancy filling effects; Table 1.13 lists them.
Class | Description |
---|---|
Brush | Is an abstract base class that is used to create brushes such as SolidBrush, TextureBrush, and LinearGradientBrush. These brushes are used to fill the interiors of graphical shapes such as rectangles, ellipses, pies, polygons, and paths. |
Brushes | Provides 140 static properties, one for the name of each color supported by Windows forms. |
HatchBrush | Allows you to fill the region by using one pattern from a large number of patterns available in the HatchStyle enumeration. |
LinearGradientBrush | Is used to create two-color gradients and multicolor gradients. By default the gradient is a linear gradient that moves from one color to another color along the specified line. |
SolidBrush | Defines a brush of a single color. Brushes are used to fill graphics shapes, such as rectangles, ellipses, pies, polygons, and paths. |
SystemBrushes | Provides a set of static properties, each named after a Windows display element, such as ActiveCaption, WindowText, and so on. Each of these properties returns a SolidBrush object that represents the color for its matching Windows display element. |
TextureBrush | A class that contains properties for the Brush object that use images to fill the interior of shapes. |
STEP BY STEP1.19 Using Different Brush Types
|
In Step by Step 1.19 you use three different Brush objects. The TextureBrush class is part of the System.Drawing namespace, and the other two classes (HatchBrush and LinearGradientBrush) are members of the System.Drawing.Drawing2D namespace.
Using HatchBrush, you filled the ellipse with the HatchStyle named HorizontalBrick. The TextureBrush class uses an image to fill the interior of a shape, and in Step by Step 1.19, the image is assumed to be in the same directory as the .exe file. If you have the image in some other directory, you need to change the path in the Bitmap constructor. The Bitmap name is a bit misleading, as it is actually capable of creating images from a variety of image formats, including BMP, GIF, JPG, and PNG.
In Step by Step 1.19 the code sets the gradient direction from the upper-right corner to the lower-left corner of the rectangle encapsulating the ellipse. Table 1.14 lists the enumeration values for LinearGradientMode.
Member Name | Description |
---|---|
BackwardDiagonal | Specifies a gradient from upper-right to lower-left |
ForwardDiagonal | Specifies a gradient from upper-left to lower-right |
Horizontal | Specifies a gradient from left to right |
Vertical | Specifies a gradient from top to bottom |
The System.Drawing.Image class provides the basic functionality for working with images. However, the Image class is abstract, which means you can create an instance of it in your class. Instead of using the Image class directly, you can use the following classes that implement the Image class functionality:
Bitmap This class is used to work with graphic files that store information in pixel-based data such as BMP, GIF, and JPEG formats.
Icon This class creates a small bitmap that represents an Windows icon.
MetaFile This class contains embedded bitmaps and/or sequences of binary records that represent a graphical operation such as drawing a line.
Step by Step 1.20 shows how to do basic operations with the Bitmap class.
STEP BY STEP1.20 Creating and Rendering Images
|
In Step by Step 1.20 you first create an image and then render it on the form's surface. The image creation code is written in the Main() method, which means it is executed before the application creates the Form object. Three key steps are related to image manipulation:
1. | You need to create a Bitmap object that can be used to work on images. The code for this creates the object by specifying its size in pixels and also specifying a format value from the PixelFormat enumeration, which belongs to the System.Drawing.Imaging namespace. The value Format32bppArgb specifies that there are 32 bits of data associated with each pixel in the image. Out of these 32 bits, 8 bits each are used for the alpha, red, green, and blue components of the pixel. |
2. | You need to get a Graphics object from the Bitmap object. This Graphics object can be used to draw on the surface of the drawing. |
3. | You need to call the Save() method on the Bitmap object. This method supports a variety of formats for saving graphics; these formats are available as static public properties of the ImageFormat class. The ImageFormat class is a member of the System.Drawing.Imaging namespace. Some of the possible properties are Bmp, Gif, Icon, Jpeg, Png, Tiff, and Wmf. |
The rest of the code in Step by Step 1.20 draws a piece of text and a curved line on the image before saving it. Note the various properties of the Pen object that are used in this program. The code uses the customized Pen object to create a boundary around the image. Table 1.15 summarizes some important properties of the Pen class.
Property | Description |
---|---|
Alignment | Specifies the alignment for the Pen object |
Brush | Specifies a Brush object that determines the attributes of the Pen object |
Color | Specifies the color of the Pen object |
DashCap | Specifies the cap style used at the end of the dashes that make up dashed lines |
DashPattern | Specifies the array of custom dashes and spaces |
DashStyle | Specifies the style used for dashed lines |
EndCap | Specifies the cap style used at the end of lines |
LineJoin | Specifies the join style for the ends of two consecutive lines |
PenType | Specifies the style of lines |
StartCap | Specifies the cap style used at the beginnings of lines |
Width | Specifies the width of the Pen object |
GUIDED PRACTICE EXERCISE 1.3You are a Windows developer for SpiderWare, Inc. The Windows application you are working on should have a form that allows users to create new designs for Spider-Webs. The requirement itself is simple: The form must have a white background, where users can design using a thin black pen. Users often make mistakes while they are designing, so there should be a mechanism to erase part of the design. Users say that they will be comfortable using the left mouse button for drawing and the right mouse button for erasing. You also noted that users of the application all have high-end machines, and they want sharper-looking designs. How would you design such a form? You should try working through this problem on your own first. If you get stuck, or if you'd like to see one possible solution, follow these steps:
If you have difficulty following this exercise, review the sections “Event Handling” and “Drawing Shapes.” The text and examples presented in those sections should help you relearn this material. After doing that review, try this exercise again. |
REVIEW BREAK
|
52.14.98.249