📄 pens.html.primary
字号:
<html>
<head>
<title>Pens and Brushes</title>
<meta name="description" content="Reliable Software Win32 Tutorial: Pens and Brushes">
<meta name="keywords" content="reliable, software, windows, cplusplus, source code, example, tutorial, object oriented, CreatePen, CreateSolidBrush, SelectObject, pen, brush, graphics, device context">
</head>
<body background="../images/grid.gif" bgcolor="white" text="black">
<table cellpadding=10 width="100%">
<tr>
<td width=100 align=center valign=middle>
<a href="../index.htm">
<img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
<br>Home</a>
<td><font face="arial" color="#009966">
<h1 align=center>Drawing with Pens and Painting with Brushes</h1>
</font>
</table>
<p>
<table width="100%">
<tr>
<td width="80" align="CENTER" valign="TOP"> <!-- Left margin -->
<i><a href="source/drawapp.zip">Download source code</a> for this tutorial (courtesy Laszlo Radanyi)</i>
<td> <!-- Middle column, there is also the right margin at the end -->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td bgcolor="#ffffff">
<hr>
<font size="+1"><b>Like a painter</b></font>, you will need pens and brushes to create artwork on your canvas. When you call Canvas::Line or Canvas::Rectangle, Windows uses the currently attached pen to draw the lines and the currently attached brush to fill the insides of the shapes.
<p>When you attach an object to the Canvas, you have to remember to detach it after you're done. Unless... you let C++ remember about that. Just use a local object whose constructor attaches, and destructor (called automatically when exiting the scope) detaches the object (see the <a href="../resource/index.htm">Resource Management</a> page for more details on this methodology). Notice that the following objects take HDC (handle to Device Context) as an argument in their constructors. However, you should simply pass them a Canvas object instead. Remember that Canvas can be automatically cast to HDC.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>StockObject</b></font>
{
public:
StockObject (HDC hdc, int type)
: _hdc(hdc)
{
_hObjOld = <font color="#000099"><b>SelectObject</b></font> (_hdc, <font color="#000099"><b>GetStockObject</b></font> (type));
}
~StockObject ()
{
<font color="#000099"><b>SelectObject</b></font> (_hdc, _hObjOld);
}
private:
HGDIOBJ _hObjOld;
HDC _hdc;
};
</font></pre>
<hr>
Windows comes with a set of pre-defined pens and brushes. It is enough to attach them to your canvas for the time you want to use them.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>WhitePen</b></font> : public <font color="#cc0066"><b>StockObject</b></font>
{
public:
WhitePen (HDC hdc): StockObject (hdc, WHITE_PEN) {}
};
<font color="#cc0066">// example</font>
void Controller::Paint (HWND hwnd)
{
PaintCanvas canvas (hwnd);
WhitePen pen (canvas);
canvas.Line (0, 10, 100, 10);
<font color="#cc0066">// destructor of WhitePen</font>
<font color="#cc0066">// destructor of PaintCanvas</font>
}
</font></pre>
<hr>
If your program keeps using a small set of non-stock pens, you might want to create them up-front (e.g. by embedding them in the View object) and use a PenHolder object to temporarily attach them to your Canvas.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>Pen</b></font>
{
public:
Pen (COLORREF color)
{
_hPen = <font color="#000099"><b>CreatePen</b></font> (PS_SOLID, 0, color);
}
~Pen ()
{
<font color="#000099"><b>DeleteObject</b></font> (_hPen);
}
operator HPEN () { return _hPen; }
private:
HPEN _hPen;
};
class <font color="#cc0066"><b>PenHolder</b></font>
{
public:
PenHolder (HDC hdc, HPEN hPen)
: _hdc (hdc)
{
_hPenOld = (HPEN)<font color="#000099"><b>SelectObject</b></font> (_hdc, hPen);
}
~PenHolder ()
{
<font color="#000099"><b>SelectObject</b></font> (_hdc, _hPenOld);
}
private:
HDC _hdc;
HPEN _hPenOld;
};
class <font color="#cc0066"><b>View</b></font>
{
public:
View ()
: _penGreen (RGB (0, 255, 128))
{}
void Paint (Canvas & canvas)
{
PenHolder holder (canvas, _penGreen);
canvas.Line (0, 10, 100, 10);
<font color="#cc0066">// destructor of PenHolder</font>
}
private:
Pen _penGreen;
};
</font></pre>
<hr>
Finally, if your program needs colored pens on-demand, i.e., you can't possibly preallocate them for all the colors you'll need, you should use colored pens. When you define an automatic ColorPen object, its constructor both creates and attaches the pen. When the destructor is called, at the end of the scope, it detaches the pen and deletes it.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>ColorPen</b></font>
{
public:
ColorPen (HDC hdc, COLORREF color)
: _hdc (hdc)
{
_hPen = <font color="#000099"><b>CreatePen</b></font> (PS_SOLID, 0, color);
_hPenOld = (HPEN)<font color="#000099"><b>SelectObject</b></font> (_hdc, _hPen);
}
~ColorPen ()
{
<font color="#000099"><b>SelectObject</b></font> (_hdc, _hPenOld);
<font color="#000099"><b>DeleteObject</b></font> (_hPen);
}
private:
HDC _hdc;
HPEN _hPen;
HPEN _hPenOld;
};
</font></pre>
<hr>
You deal with Brushes in exactly the same way (there are, however, more types of brushes supported by Windows). For instance, here's a definition of a ColorBrush.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>ColorBrush</b></font>
{
public:
ColorBrush (HDC hdc, COLORREF color)
: _hdc (hdc)
{
_hBrush = <font color="#000099"><b>CreateSolidBrush</b></font> (color);
_hBrushOld = (HBRUSH)<font color="#000099"><b>SelectObject</b></font> (_hdc, _hBrush);
}
~ColorBrush ()
{
<font color="#000099"><b>SelectObject</b></font> (_hdc, _hBrushOld);
<font color="#000099"><b>DeleteObject</b></font> (_hBrush);
}
private:
HDC _hdc;
HBRUSH _hBrush;
HBRUSH _hBrushOld;
};
</font></pre>
<hr>
As always, you are encouraged to experiment on your own.
<p>And now for something completely different: <a href="active.html">Threads</a>
<hr>
</table>
<td width=60>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -