![](/user_photo/_userpic.png)
Pro Visual C++-CLI And The .NET 2.0 Platform (2006) [eng]-1
.pdf468 |
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
private:
System::Void Form1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
//build a point from x,y coords of mouse click Point p = Point(e->X, e->Y);
//did we click in the intersection?
if (Rectangle::Intersect(rect1, rect2).Contains(p)) Text = "Intersection and Union";
// did we click in the union?
else if (Rectangle::Union(rect1, rect2).Contains(p)) Text = "Union";
// did we miss altogether else
Text = "Outside of Both";
}
};
}
The first thing you need to do is declare and build two rectangles that you will make the mouse check against:
Drawing::Rectangle rect1;
Drawing::Rectangle rect2;
//... |
|
|
// Build the rectangles |
from points and size |
|
Drawing::Point point1 = |
Drawing::Point(25,25); |
|
Drawing::Point point2 |
= |
Drawing::Point(100,100); |
Drawing::Size size |
= |
Drawing::Size(200, 150); |
rect1 = Drawing::Rectangle(point1, size); rect2 = Drawing::Rectangle(point2, size);
You will learn about the DrawRectangle() method later, but as you can see in the code, it takes a Pen to draw with and then the Rectangle to draw:
g->DrawRectangle(Pens::Black, rect1);
Finally, in the MouseDown event, you check to see where the mouse was clicked and place the results in the title:
//build a point from x,y coords of mouse click Point p = Point(e->X, e->Y);
//did we click in the intersection?
if (Rectangle::Intersect(rect1, rect2).Contains(p)) Text = "Intersection and Union";
// did we click in the union?
else if (Rectangle::Union(rect1, rect2).Contains(p)) Text = "Union";
// did we miss altogether? else
Text = "Outside of Both";
Figure 11-7 shows the mouse being clicked in the intersection of the two rectangles in InterOrUnion.exe.
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO512x1.jpg)
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
469 |
Figure 11-7. It’s an intersection.
Region
The last of the utility types is the only class in the bunch. Region is a neat little class in that it alters itself with the help of other rectangles and regions into a more complex region. The alterations that the Region class does are things such as unions, intersections, exclusive or, and complements. A Region class has no properties of its own; instead, it is made up of a number of methods (see Table 11-8) that it uses to alter itself.
Table 11-8. Common Region Members
Member |
Description |
Complement() |
Alters itself to become the complement of itself. The region of the |
|
complement is restricted by a specified rectangle. |
Exclude() |
Alters itself to become the portion of the region that does not intersect with |
|
the given rectangle or region. |
GetBounds() |
Specifies the smallest rectangle that the region can be contained within. |
Intersect() |
Alters itself to become the intersection of itself and a specified rectangle |
|
or region. |
IsEmpty() |
Specifies whether the region is made up of an empty area. |
IsInfinite() |
Specifies whether the region is infinite in size. |
MakeEmpty() |
Sets the region to empty. |
MakeInfinite() |
Sets the region to infinite. |
Transform() |
Transforms itself using a matrix. |
Translate() |
Translates itself by a specified amount. |
Union() |
Alters itself to become the union of itself and a specified rectangle or region. |
Xor() |
Alters itself to become the exclusive or (the union minus the intersection) of |
|
itself and a specified rectangle or region. |
|
|
470 |
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
Listing 11-8 shows some of these methods in action.
Listing 11-8. Displaying a Region
namespace |
RegionEx |
{ |
|
using |
namespace System; |
using |
namespace System::ComponentModel; |
using |
namespace System::Collections; |
using |
namespace System::Windows::Forms; |
using |
namespace System::Data; |
using |
namespace System::Drawing; |
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
Drawing::Point point1 = Drawing::Point(25,25);
Drawing::Point point2 |
= Drawing::Point(100,100); |
||
Drawing::Size size |
= Drawing::Size(200, 150); |
||
Rectangle |
rect1 |
= |
Drawing::Rectangle(point1, size); |
Rectangle |
rect2 |
= |
Drawing::Rectangle(point2, size); |
region = gcnew Drawing::Region(rect1); region->Xor(rect2);
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
private:
System::ComponentModel::Container ^components; Drawing::Region ^region;
#pragma region Windows Form Designer generated code void InitializeComponent(void)
{
this->SuspendLayout();
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(322, 273);
this->Name = L"Form1";
this->Text = L"Filling A Region";
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO514x1.jpg)
472 |
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
Drawing Strings
Drawing strings almost doesn’t require a section of its own—all it involves is a single call to the DrawString() method found in the Graphics class. The more difficult part of drawing strings is setting up the font and color you want to print with. (I cover both topics later.)
Now you’ll take a quick peek at the DrawString() method. If you were to look at the .NET Framework documentation, you’d find a plethora of overloads. When you examine them more closely, you’ll discover that they all start with the parameters String, Font, and Brush. From there, it gets a little tricky because you have to decide if you just want to specify the starting upper-left corner of where you want the string displayed, using either (x, y) coordinates or a Point, or specify the entire rectangle that you want to restrict the string to.
g->DrawString(string, font, brush, xF, yF); g->DrawString(string, font, brush, pointF); g->DrawString(string, font, brush, rectangleF);
When you restrict the string to a rectangle, the text automatically word-wraps, as Listing 11-9 shows. It unfortunately will also show half of a line of text if the vertical height is not enough.
Listing 11-9. Drawing a String to a Rectangle
namespace |
StringRect |
{ |
|
using |
namespace System; |
using |
namespace System::ComponentModel; |
using |
namespace System::Collections; |
using |
namespace System::Windows::Forms; |
using |
namespace System::Data; |
using |
namespace System::Drawing; |
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
private:
System::ComponentModel::Container ^components;
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO516x1.jpg)
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
473 |
#pragma region Windows Form Designer generated code void InitializeComponent(void)
{
this->SuspendLayout();
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(292, 273);
this->Name = L"Form1";
this->Text = L"String in a Rectangle"; this->Paint +=
gcnew System::Windows::Forms::PaintEventHandler(this, &Form1::Form1_Paint);
this->ResumeLayout(false);
}
#pragma endregion
private:
System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)
{
// Draw the string e->Graphics->DrawString(
"Let's draw a string to a rectangle and go a little " "overboard on the size of the string that we place " "inside of it",
gcnew Drawing::Font(gcnew FontFamily("Arial"), 12), Brushes::Black, Drawing::RectangleF(20.0, 40.0, 260.0, 50.0));
}
};
}
Figure 11-9 shows that StringRect.exe draws a string to a rectangle that is too small.
Figure 11-9. A string restricted to a too-small rectangle
In reality, each of the overloads for the DrawString() method listed previously has one more parameter of type StringFormat, which has been defaulted to GenericDefault.
g.DrawString(string, font, brush, xF, yF, stringformat); g.DrawString(string, font, brush, pointF, stringformat); g.DrawString(string, font, brush, rectangleF, stringformat);
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO517x1.jpg)
474 |
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
StringFormat is a class containing several properties (see Table 11-9) that allow the DrawString() method to do things such as draw the text vertically and left-, right-, or center-align it.
Table 11-9. Common StringFormat Properties
Property |
Description |
Alignment |
Specifies alignment of the text |
FormatFlags |
Specifies StringFormatFlags such as DirectionVertical and NoWrap |
GenericDefault |
A static method that gets the generic default StringFormat object |
GenericTypographic |
A static method that gets the generic typographic StringFormat object |
LineAlignment |
Specifies line alignment |
Trimming |
Specifies how to trim a string that doesn’t fit completely within a |
|
display area |
|
|
Listing 11-10 shows the same text as shown earlier, but this time it is written in a downward direction and centered on each line.
Listing 11-10. Drawing Strings Downward in a Rectangle
namespace |
DownwardStringRect |
{ |
|
using |
namespace System; |
using |
namespace System::ComponentModel; |
using |
namespace System::Collections; |
using |
namespace System::Windows::Forms; |
using |
namespace System::Data; |
using |
namespace System::Drawing; |
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
private:
System::ComponentModel::Container ^components;
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO518x1.jpg)
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO519x1.jpg)
476 |
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
Fonts
It seems that many people seem overly concerned about the differences between GDI+’s Font class and FontFamily class. Here’s my take on it: A Font class represents a single font and a FontFamily class represents a group of fonts that share many characteristics. You might think of a font family as “Arial” and a font as “Arial, 10-point, italic.”
When you draw strings with GDI+, you don’t have much of a choice. You have to build a Font class. You can’t draw a string with a FontFamily class.
When you build a Font class, you have the choice of starting with a FontFamily class or a String containing the name of a font family. You’ll probably use a String if you’re planning on building a Font class from one of the standard fonts found on a computer (e.g., Arial, Courier, and Times New Roman). On the other hand, if your font is a little less common, you probably will search the computer for a list of font families currently loaded on your computer. If you find the FontFamily class in the list of font families, then it’s a simple matter of using the FontFamily class instead of the String containing the font family’s name. In general, I don’t find the FontFamily class that useful as I tend to use the more common fonts in my programs, but you might have more exotic tastes. Basically, to use the FontFamily class, just replace the String in the first parameter of the Font constructor with the FontFamily class.
The process of building a font is quite easy. You do it using the Font constructors. You will use three constructors most often. They are really the same except that parameters are defaulted for two of them.
The first constructor has no defaulted values and takes the name of the font family and the unit size, the font style, and the graphics unit:
Font ^f = gcnew Drawing::Font("Arial", 16, FontStyle::Bold,GraphicsUnit::Point);
In most cases, fonts default to a graphics unit of pixels. Therefore, Font provides a constructor with the graphics unit defaulted to pixels:
Font ^f = gcnew Drawing::Font("Arial", 16, FontStyle::Bold);
In addition, most of the time you are going to work with the font in the regular font style (not boldface, italic, or underline). So, again, Font provides a default for this:
Font ^f = gcnew Drawing::Font("Arial", 16);
Even though the Font class has several properties (see Table 11-10), they are all read-only. In other words, you can’t change a font once you have constructed it.
Table 11-10. Common Font Properties
Property |
Description |
Bold |
true if the font is boldface |
FontFamily |
Gets the font family |
Height |
Gets the height of the font in the current graphics unit |
Italic |
true if font is italicized |
Name |
Gets the name of the font |
Size |
Gets the size of the font in the current graphics unit |
SizeInPoints |
Gets the size of the font in points (1/72 inch) |
![](/html/611/317/html_pEm09UKvKG.bCRW/htmlconvd-IXrUrO520x1.jpg)
C H A P T E R 1 1 ■ G R A P H I C S U S I N G G D I + |
477 |
Table 11-10. Common Font Properties
Property |
Description |
Strikeout |
true if the font is struck out |
Style |
Gets the style information |
Underline |
true if the font is underlined |
Unit |
Gets the graphics unit |
|
|
The code in Listing 11-11 creates ten random fonts and then displays them.
Listing 11-11. Generating Random Fonts
namespace |
FontsGalore |
{ |
|
using |
namespace System; |
using |
namespace System::ComponentModel; |
using |
namespace System::Collections; |
using |
namespace System::Windows::Forms; |
using |
namespace System::Data; |
using |
namespace System::Drawing; |
using |
namespace System::Drawing::Text; |
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
fonts = gcnew array<Drawing::Font^>(10); fontstr = gcnew array<String^>(10);
// Used to generate random fonts array<float>^ sizes = gcnew array<float> {
10.0, 12.5, 16.0
};
array<FontStyle>^ fontstyles = gcnew array<FontStyle> { FontStyle::Regular, FontStyle::Bold, FontStyle::Italic,
(FontStyle)(FontStyle::Underline|FontStyle::Bold|FontStyle::Italic)
};
array<GraphicsUnit>^ units = gcnew array<GraphicsUnit> { GraphicsUnit::Point, GraphicsUnit::Pixel
};
// Get all fonts on computer InstalledFontCollection ^availFonts =
gcnew InstalledFontCollection();