Visual C++ 2005 Express provides graphic support based on GDI+ (Graphics Device Interface), a graphics library. GDI+ is implemented in .NET through properties and methods made available by classes organized within the System::Drawing namespace. It offers support for managing and displaying graphics images, drawing vector graphics, and drawing text.
Hint | GDI+ (Graphics Device Interface) is a graphics system that allows applications to create graphics and draw text. |
GDI+ draws graphics using a coordinate system. Coordinates are measured using pixels. A graphic is rendered by specifying its starting position relative to coordinates (0,0) and other required coordinates to render a particular shape based on their distance from (0,0) on the x and y axes, as depicted in Figure 10.5.
Figure 10.5: A graphical depiction of the coordinate system employed by GDI+ when drawing graphics.
Hint | A pixel (picture element) is a unit of measure. The computer's display is measured in terms of the number of pixels that it displays (such as 800×600, 1024×786, and so on). |
As you have seen in previous chapter games, you can configure the PictureBox control's Image property to display a graphics image. You also learned through the creation of the Dice Poker game, shown in Figure 10.6, that you can preload graphics images into an ImageList control and then display these images in any control that is capable of displaying them.
Figure 10.6: An example of an application that uses the PictureBox and ImageList controls to work with graphics.
GDI+ support for images also includes the ability to manipulate them in many different ways, including stretching, centering, and zooming.
Along with the ability to render an image, GDI+ gives Visual C++ the capability of drawing using coordinates passed to various methods. Visual C++ allows you to draw on various surfaces, including Button and Form backgrounds. You can execute methods that can draw such elements as lines, ellipses, rectangles, polygons, arcs, and curves. For example, if you want to draw an ellipse, just call the correct method and give it coordinates of where to draw.
To draw graphics, you need a surface to draw on, such as a Form or Button control. But before you can begin drawing, you must create a Graphics object for the drawing surface you want to use. The first step in doing so is to create a handle to the instance of the Graphics class within your application, as demonstrated in the following example:
System::Drawing::Graphics ^FormGraphic;
After you have established this handle, you can use it to obtain an instance of the surface that you want to draw on by calling the CreateObjects() method of the object that the surface belongs to. This next example demonstrates the concept:
private: System::Void Form1_Load(System::Object^ sender,\ System::EventArgs^ e) { FormGraphic = this->CreateGraphics(); }
In this example, the FormGraphic object has been set to the drawing surface of Form1 (represented by this because it is being done within the Form1 class). After the handle has been defined and the drawing surface has been established, you can begin drawing graphics within your application by calling on any of the Graphics class's methods, as listed in Table 10.1.
Method | Description |
---|---|
Clear | Clears the drawing surface |
DrawArc | Draws an arc |
DrawBezier | Draws a Bezier curve |
DrawBeziers | Draws a collection of Bezier curves |
DrawClosedCurve | Draws a closed curve |
DrawCurve | Draws a curve |
DrawEllipse | Draws an ellipse |
DrawIcon | Draws an icon |
DrawIconUnstretched | Draws the image without scaling it |
DrawImage | Draws an Image |
DrawImageUnscaled | Draws an image without scaling its size |
DrawLine | Draws a line |
DrawLines | Draws a collection of line segments |
DrawPath | Draws a graphics path |
DrawPie | Draws a pie shape |
DrawPolygon | Draws a polygon |
DrawRectangle | Draws a rectangle |
DrawRectangles | Draws a collection of rectangles |
DrawString | Draws a text string |
FillClosedCurve | Draws a filled curve |
FillEllipse | Draws a filled ellipse |
FillPath | Draws a filled path |
FillPie | Draws a filled pie |
FillPolygon | Draws a filled polygon |
FillRectangle | Draws a filled rectangle |
FillRectangles | Draws a collection of filled rectangles |
FillRegion | Draws a filled region |
One way in which to draw a graphic using the Graphics class is with the Pen class. This is done as follows:
FormGraphic->DrawLine( pen, ptStart, ptEnd );
In this example, pen represents a Pen object, and ptStart and ptEnd represent Point objects that determine the starting and ending points for a line. You can find the Pen class in the System::Drawing namespace. It allows you to specify how you want a given image to be drawn. One Pen property is Color, which allows you to specify the color of the line to be drawn. Another Pen property is Brush, which retrieves or sets a Brush object for the Pen. Using methods associated with the Brush class, you can draw filled-in shapes.
To define a color when drawing shapes with the Pen class or filling in shapes with the Brush class, you can specify any of a large collection of predefined colors that are provided by these classes. Table 10.2 shows a complete list of the colors provided by these two classes.
AliceBlue | DarkTurquoise | LightSkyBtue | Pink |
AntiqueWhite | DarkViolet | LightSlateGray | Plum |
Aqua | DeepPink | LightSteelBlue | PowderBlue |
Aquamarine | DeepSkyBlue | LightYellow | Purple |
Azure | DimGray | Lime | Red |
Beige | DodgerBlue | LimeGreen | RosyBrown |
Bisque | Firebrick | Linen | RoyalBlue |
Black | FloralWhite | Magenta | SaddleBrown |
BlanchedAlmond | ForestGreen | Maroon | Salmon |
Blue | Fuchsia | MediumAquamarine | SandyBrown |
BlueViolet | Gainsboro | MediumOrchld | SeaGreen |
Brown | GhostWhite | MediumPurple | SeaShell |
BurlyWood | Gold | MediumSeaGreen | Sienna |
CadetBlue | Goldenrod | MediumSlateBlue | Silver |
Chartreuse | Gray | MediumSpringGreen | SkyBlue |
Chocolate | Green | MediumTurquoise | SlateBlue |
Coral | GreenYellow | MediumVioletRed | SlateGray |
CornflowerBlue | Honeydew | MidnightBlue | Snow |
Cornsilk | HotPink | MintCream | SpringGreen |
Crimson | IndianRed | MistyRose | SteelBlue |
Cyan | Indigo | Moccasin | Tan |
DarkBlue | Ivory | NavajoWhite | Teal |
DarkCyan | Khaki | Navy | Thistle |
DarkGoldenrod | Lavender | OldLace | Tomato |
DarkGray | LavenderBlush | Olive | Transparent |
DarkGreen | LawnGreen | OliveDrab | Turquoise |
DarkKhaki | LemonChiffon | Orange | Violet |
DarkMagenta | LightBlue | OrangeRed | Wheat |
DarkOliveGreen | LightCoral | Orchid | White |
DarkOrange | LightCyan | PaleGoldenrod | WhiteSmoke |
DarkOrchid | LightGoldenrodYellow | PaleGreen | Yellow |
DarkRed | LightGray | PaleTurquoise | YellowGreen |
DarkSalmon | LightGreen | PaleVioletRed | |
DarkSeaGreen | LightPink | PapayaWhip | |
DarkSlateBlue | LightSalmon | PeachPuff | |
DarkSlateGray | LightSeaGreen | Peru |
The best way to learn how to work with the Graphics class is to experiment with it. Let's begin with a couple of quick examples. The first example, shown next, demonstrates how to draw a green square:
private: System::Void button1_C1ick(System::Object^ sender, \ System::EventArgs^ e) { //Handle to form graphic surface System::Drawing::Graphics^ FormGraphic; //Handle to pen System::Drawing::Pen^ drawingPen; //Instantiate a pen object drawingPen = gcnew System::Drawing::Pen( \ System::Drawing::Color::Black ); //Create a rectangle object to hold the drawing extents System::Drawing::Rectangle drawingRect(100, 100, 100, 100); //Obtain the form's graphic surface FormGraphic = this->CreateGraphics(); //Draw the image FormGraphic->DrawRectangle( drawingPen, drawingRect ); }
In this example, the program statements that draw the square are executed after the user clicks on the Button control. The first statement defines an object named FormGraphic based on the System::Drawing::Graphics class. The second statement defines an object named drawingPen, setting the object's Color property to black. The third statement uses the Rectangle class to instantiate an object named drawingRect so that it can represent the drawing extents for the rectangle to be drawn. The fourth statement sets the form's background as the drawing surface. Finally, the statement draws on the form's surface, using the data stored in the drawingPen and drawingRect objects.
Trick | Although the method used in this example is called Rectangle, you can draw squares, too, as long as the coordinates you specify for the rectangle create a square. |
Figure 10.7 shows the drawing that is produced when this example is executed.
Figure 10.7: Using the Graphics class's DrawRectangle method to draw a shape.
The next example demonstrates how to draw a filled-in circle. As you can see, the method is similar to the previous example:
private: System::Void button1_Click(System::Object^ sender, \ System::EventArgs^ e) { //Handle to form graphic surface System::Drawing::Graphics^ FormGraphic; //Handle to pen System::Drawing::Brush^ drawingBrush; //Instantiate a brush object drawingBrush = gcnew System::Drawing::SolidBrush( \ System::Drawing::Color::Green ); //Create a rectangle object to hold the drawing extents System::Drawing::Rectangle drawingRect(100, 100, 100, 100); //Obtain the form's graphic surface FormGraphic = this->CreateGraphics(); //Draw the image FormGraphic->FillEllipse(drawingBrush,drawingRect); }
As with the previous example, this example draws a shape (this time a filled-in circle) after the user clicks on the Button control. The first statement defines an object named FormGraphic based on the System::Drawing::Graphics class. The second statement creates an object named drawingPen, setting its Color property to green. The third statement again uses the Rectangle class to instantiate an object named drawingRect, which holds the bounds of the ellipse. The fourth statement sets the form's background as the drawing surface, as before. The last statement draws the filled ellipse on the form's surface based on the information stored in drawingBrush and drawingRect.
Trick | Although the Graphics class does not provide a FillCircle method, you can create a filled circle using FillEllipse by giving it a rectangle that is equal on all sides. |
Figure 10.8 shows the drawing that is produced when this example is executed.
Figure 10.8: Drawing a filled-in circle using the Graphics object's FillEllipse method.
In addition to displaying and drawing graphics images, Visual C++'s GDI+ implementation allows you to draw text as a graphics image. You can do this using the Graphics class's DrawString() method. For example, one way to call on this method is shown here:
Dim objName As System::Drawing::Graphics objName(TextString, FontType, BrushColor, Coordinates)
The following statement demonstrates how to create a text graphic:
private: System::Void Forml_Paint(System::Object^ sender, \ System::Windows::Forms::PaintEventArgs^ e) { System::Drawing::Font^ drawingFont; //Create a font object drawingFont = gcnew System::Drawing::Font("Arial", 18, FontStyle::Bold ); //Obtain the form's graphic surface //Draw the string using the PaintEventArgs handle e->Graphics->DrawString("Hello World!", \ drawingFont, Brushes::Red, 50, 50); }
In this example, the statements that draw the text image have been placed inside the Form1_Paint function. This function automatically executes each time the form needs to be repainted. Unlike with the earlier examples, if you do something that causes the form to be repainted (such as task to another program and then return), the text still appears because it is redrawn each time the form repaints itself.
In this example's first statement, a Font object named drawingFont is instantiated and passed arguments that set its font type, font size, and font style. The second statement draws a text string using the Graphics class's DrawString method. Note that the Graphics class is referenced through e->Graphics in this example. This reference is possible because painting event handlers automatically generate a handle to PaintEventArgs, which contains a reference to the System::Drawing class. This is expressed as the handle named e.
Trick | If you need to write code that responds to events generated by your application, select the Events icon in the Properties window while in Design view. Type in any function name you like for the event you want to respond to, and Visual C++ automatically generates a function so that you can write code that activates when the event triggers. |
Figure 10.9 shows the output generated when this example is run.
Figure 10.9: Visual C++ allows you to draw text as a graphic.