【转载】画笔与画刷VC(2)

原文地址:http://www.quanxue.cn/JC_CLanguage/Sdk/Sdk07.html

Windows 图像用户接口(GUI)通过在设备场景上绘制来提高可视化的性能。这需要你了解如何创建和使用画刷与画笔。在这个画刷与画笔的演示程序里,你将创建几种不同类型的画刷与画笔,并利用他们进行绘制,还能看到如何改变它们的创建方式以及在 DC 上绘制的方式。这里还会有很多使用画刷与画笔的绘制方法的演示。
  在 Polygon( ) 这样的函数内使用点的数组填充和描绘多边形的轮廓。通过 FrameRect( ) 函数,可以让画刷像画笔一样使用。位图可以由文件导入并使用画笔和画刷进行喷绘。为了可视化的显示闪屏,需要创建一个弹出窗口,使用系统计时器,然后在上面绘制一个“HELLO”。所有的窗体背景都是由画刷喷绘的,每当需要喷绘背景的时候,WM_ERASEBKGND 消息就会发送给窗体。
呈现在这个例子中的很多新东西
  有很多基本的图形绘制操作出现在这个例子中,需要一次了解很多,你可以通读本文,然后选择其中一部分比如“画笔,一个图形对象”。你可以创建自己的程序,使用一两个按钮,从本例中复制一些画笔创建的代码。你可以赋值一个过程如“ procedure PenDraw;”到你的按钮单击过程,然后复制一些画笔绘制函数如 MoveToEx( ) 和 LineTo( ),看看在画笔创建过程中你需要改变哪些参数,以及 SetROP2( ) 如何得到不同的绘制效果。再添加另一个过程如“procedure DrawPolyGon;”到另一个按钮的单击过程,并复制点的数组以及 Polygon( ) 函数的代码,然后改变点的数组(点的数量、点的位置)来绘制你需要的多边形,这样有助于你理解它是如何工作的。接下来添加 WM_PAINT 消息并复制相应代码,增加画刷创建代码,改变参数看看它会导致哪些不一样。使用 API 绘制方法将依靠你的变化和实践,直到你有了很多可用选项的相关知识。
画笔,一个图形对象
  和字体一样,画笔也是一个图形对象,所以你可以创建和删除一个用于设备场景上绘制的画笔。画笔是程序进行绘制直线和曲线的工具。 Delphi VCL 使用 TPen 封装了这个图形对象。有两种类型的画笔:逻辑修饰画笔和几何画笔。逻辑修饰画笔使用一个像素宽度快速绘制直线,几何画笔用于绘制宽度大于一像素的直线、点划线或可缩放线。画笔可以被创建,所以它可以使用点或短划线绘制非连续线。有三种画笔存储对象:BLACK_PEN、 WHITE_PEN 和 NULL_PEN 。设备场景的默认画笔就是存储对象的黑色画笔。你可以使用 CreatePen( ) 创建画笔:
function CreatePen(Style, Width: Integer; Color: TColorRef): HPEN;
  或者利用 TLogPen 记录使用 CreatePenIndirect( ) 函数:
function CreatePenIndirect(const LogPen: TLogPen): HPEN;


PLogPen = ^TLogPen;
tagLOGPEN = packed record
lopnStyle: Cardinal;
lopnWidth: TPoint;
lopnColor: TColorRef;
end;
TLogPen = tagLOGPEN;
  几何画笔可以使用 ExtCreatePen( ) 函数创建:
function ExtCreatePen(PenStyle, Width: Cardinal;
const Brush: TLogBrush; StyleCount: Cardinal;
Style: Pointer): HPEN;
创建画笔的参数
Style 参数
  有八种预定义的画笔风格。短划线和点只有在逻辑修饰画笔时有效,宽度为一像素。
PS_SOLID - 绘制实线
PS_DASH - 使用短划线绘制
PS_DOT - 使用点绘制
PS_DASHDOT - 使用点和短划线绘制
PS_DASHDOTDOT - 使用一个短划线带两个点方式绘制
PS_NULL - 不绘制线
PS_INSIDEFRAME - 强制线在形状内绘制
PS_USERSTYLE - 用户自定义绘制方式。该风格只有使用 ExtCreatePen( ) 函数时有效。
Width 参数
  这里设置画笔宽度。取值为 1 创建逻辑修饰画笔,任何大于 1 的值创建几何画笔。
Color 参数
  这里使用 TColorRef 类型,这是绿、蓝、红颜色值的十六进制表示,绿为 $FF0000 、蓝为 $00FF00、红为 $0000FF。
背景颜色
  如果你使用短划线或点创建并绘制线条,你会认为线条(短划线或点)颜色就是画笔的 color 参数,确实如此,但是在短划线或点之间的间隔处是什么颜色?就像字体的绘制一样,DC 的背景色被用在这里了。如果你使用
OldColor := SetBkColor(TempDC, $0000FF); ,
  那么间隔处颜色将是红色。如果你不想填充间隔的颜色,你也可以设置背景模式为 Transparent :
SetBkMode(TempDC, TRANSPARENT);
  HDC 背景颜色同样适用于填充画刷图案的背景色。
画刷
  和字体一样,画刷也是一个图形对象,所以你可以创建和删除一个用于设备场景上绘制的画笔。画刷是用来喷绘(填充)形状或区域内部的图形工具。你可以使用画刷绘制形状、填充矩形或椭圆的内部、绘制圆形图表的一部分以及喷绘其他统计图形。有两种类型的画刷:逻辑画刷和物理化刷。逻辑画刷是一个位图的描述(参数值),程序可以用它喷绘形状。物理画刷是设备场景基于逻辑画刷参数创建的实际的 8*8 的位图。这两者比较像逻辑字体与物理字体的关系。有 4 个函数用于创建画刷:
CreateSolidBrush($FF0000) 用于实心的画刷。
CreateHatchBrush(HS_HORIZONTAL, $FF00FF) 用于图形填充的画刷,可以使用六种填充图形参数,列举如下:
HS_HORIZONTAL - 使用水平线
HS_VERTICAL - 使用竖直线
HS_FDIAGONAL - 使用左斜线
HS_BDIAGONAL - 使用右斜线
HS_CROSS - 使用十字交叉线
HS_DIAGCROSS - 使用斜向交叉线
  填充画刷的背景颜色使用 HDC 的背景色填充,可以通过 SetBkColor( ) 改变它。如果 HDC 背景色模式为 TRANSPARENT ,那么将没有背景色填充这个画刷。
  要使用位图作为画刷需要调用下面这个函数。
  CreatePatternBrush(hBitmap1) 将使用位图画刷。如果你使用
  CreateBrushIndirect(BrushLog1);  那么你可以创建三种类型的画刷。
  图形填充画刷使用一个 8*8 的位图,这个位图可以比 8*8 大,但是不能小。由于位图被用于画刷的组成图案,所以接下来要介绍一下位图的信息。
画刷使用的位图
  位图因为每个像素的不同数量的位(1bit、4bit、8bit、16bit、24bit、32bit)而开始变得复杂了,位图可以使用它们的调色板和颜色面板,位图分为设备无关位图(DIB)和设备相关位图(DDB)。这里不准备做过多解释,只是给出足够的使用图形画刷的信息,以及使用像素转换函数 BitBlt( ) 在 hDC 上绘制。本例创建的第一个画刷是 Brush4 ,它从程序资源内导入一个位图,使用代码:
Bitmap2 := LoadBitmap(hInstance,'BRUSH');
  Bitmap2 是从函数返回的位图的句柄,这个句柄不是 hDC ,也没有 hDC 属性。你不能在上面绘制任何东西,也不能使用 hDC 像素转换函数,直到你赋值一个内存 hDC 给它,后面会有使用位图的进一步探讨……你可以使用位图句柄创建一个图形画刷。通过 BrushLog1,你可以设置 BrushLog1.lbStyle 为 BS_PATTERN ,然后设置 BrushLog1.lbHatch 为位图句柄,然后调用 CreateBrushIndirect(BrushLog1).
BrushLog1.lbStyle := BS_PATTERN;
BrushLog1.lbHatch := Bitmap2;
Brush4 := CreateBrushIndirect(BrushLog1);
DeleteObject(Bitmap2);
  Brush4 在画刷创建之后没有使用或涉及到 Bitmap2,因为 Bitmap2 句柄已经不再需要了,这个对象被删除了。通过位图资源,这是创建位图画刷的最为常用的方法。通过 Brush5 ,我们创建一个位图,设置它的像素,并赋值给一个图形画刷。
位图的每个像素
  参阅“function MakeBrush5: THandle;”部分。如果你要创建的位图只在你自己的程序内使用,那么使用设备相关位图是比较容易的方法。CreateCompatibleBitmap( ) 设置一个设备相关位图来匹配(每像素位数、调色板)你作为参数给出的 hDC 。由于我们在创建主窗体之前调用了 MakeBrush5 ,我们还没有能够得到 hDC 的窗体。如果你使用 TempDC := GetDC(0); 它将返回桌面的 hDC。下面为多个 hDC 调用使用 TempDC 。
TempDC := GetDC(0);
Bitmap2 := CreateCompatibleBitmap(TempDC,8,8);
BmpDC := CreateCompatibleDC(TempDC);
ReleaseDC(GetDesktopWindow,TempDC);
SelectObject(BmpDC,Bitmap2);
  CreateCompatibleBitmap 返回一个 8*8 的位图的句柄,位图与桌面有一样的颜色属性(每像素位数、调色板)。由于我们只使用两种颜色(黑白),所以并不关心调色板和每像素位数。CreateCompatibleDC(TempDC); 返回内存设备场景。内存设备场景有一个只存在于内存(位图的像素数组)的显示表面。这个新创建的 BmpDC 只有一个白色像素并没有什么用处。当 SelectObject(BmpDC,Bitmap2); 被调用时,BmpDC 将和 Bitmap2 有一样的宽度、高度和颜色信息。现在在 BmpDC 上面绘制将会改变 Bitmap2 的像素。现在我们看看 BmpDC 的使用:
Dot := 0;
for i:= 0 to 7 do
begin
for k:= 0 to 7 do
if ((k+Dot) mod 2) <> 0 then SetPixelV(BmpDC,i,k,$00000000)
else SetPixelV(BmpDC,i,k,$00FFFFFF);
Inc(Dot);
end;
  SetPixelV( ) 将会设置 BmpDC 的每个像素的颜色。使用 “if ((k+Dot) mod 2) <> 0” 将设置像素黑白交替。黑白交替的位图将设置为图形画刷 Brush5 的填充图案。这个画刷将用于特殊的画刷效果。
  参阅“function StripeBrush(Clr1, Clr2: DWORD; Horz: Boolean): THandle;”,它将创建一个类似 Brush5 里面的位图,但是它用循环绘制斑纹有所不同:
for i:= 0 to 7 do
begin
for k := 0 to 7 do
case i of
1,2,5,6: if Horz then SetPixelV(BmpDC, i, k, Clr1) else SetPixelV(BmpDC, k, i, Clr1);
else
if Horz
then SetPixelV(BmpDC, i, k, Clr2)
else SetPixelV(BmpDC, k, i, Clr2);
end;
end;
  for 循环将会使用 Clr1 和 Clr2 两种颜色创建水平或竖直条纹位图。这个 for 循环遍历了 8*8 位图的所有 64 个像素,所以你可以在运行期创建一个自定义的位图画刷。
使用画笔和画刷
  我们需要一个显示表面来观察绘制了什么, TempDC := GetDC(hMainForm); 将会得到主窗体的 DC 。如果使用基本的绘制函数如 Rectangle( ) 或 Ellipse( ) ,那么当前画刷和画笔将被用在 DC 上绘制。默认画刷为白色,默认画笔为黑色。使用:
OldBrush := SelectObject(TempDC, Brush1);
OldPen := SelectObject(TempDC, Pen1);
  将会改变当前画刷或画笔。
- 使用画笔绘制
  参见下面例子中的 procedure PenDraw; 过程。这个画笔绘制的几行代码使用三种不同的画笔进行绘制,SetROP2( ) 用于改变画笔与背景色的混合方式,参见下面的表格看看 fnDrawMode 参数的逻辑运算。SetROP2 也在 Rectangle( ) 和 Polygon( ) 时改变画刷与画笔以及画刷的混合效果。如果你调用 SetROP2(TempDC, R2_NOT); 使用任何颜色的笔绘制直线,线条和目标像素的颜色反置进行绘制,如果你再次在这个位置绘制那么颜色又被反置恢复为以前的颜色。浏览一下下面的表格,我不准备解释逻辑运算以及你将在屏幕上看到的结果,除了R2_BLACK (黑色像素)、 R2_WHITE (白色像素)、R2_NOP (不变)和 R2_COPYPEN (画笔颜色)。其他操作依赖于目标 hDC 的颜色、画笔的颜色或者两者都有、还有逻辑运算。如果你理解或对 RGB 颜色很有经验,你可以实践试试不同的光栅混合操作模式来看看它对你是否有用。
  有几个多点绘制函数,比如 PolyLine( )、 PolyPolyline( ) 或 Polygon( ),为了使用它们你需要设置一个点的数组,给出每个笔的绘制点位置(参见下面的 procedure DrawIt; 和 procedure PaintIt; 代码)。
- 使用画刷绘制
  FillRect( ) 可被用于绘制一个矩形,内部填充作为参数给出的画刷。你可以使用系统颜色的画刷,如:FillRect(TempDC, Rect1, COLOR_ACTIVECAPTION+1);
  PatBlt( ) 函数使用当前画刷填充一个 Rect ,但是和 Rectangle( ) 不同的是,它不使用画笔绘制轮廓,它有一个光栅操作码,这对背景颜色混合或反置是比较有用的。PatBlt(TempDC, 50, 70, 66, 28, PATCOPY); 将把当前画刷作为矩形复制到 TempDC 。注意这里 dwRop 为 PATCOPY ,Win32 API 帮助只列举了 5 种 dwRop 代码,但是还有其他一些没列出来。

你可能感兴趣的:(【转载】画笔与画刷VC(2))