第二章
cxScreen = GetSystemMetrics (SM_CXSCREEN) ; //得到系统的硬件的某些参数
cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
RECT rt;
GetClientRect(hWnd, &rt); //得到客户区矩形区
//sprintf(buf," %d",4); // 格式化输出文本
wsprintf(buf," %d",6);
TextOut(hdc,10,10,buf,strlen(buf));
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
第三章
HICON LoadIcon(HINSTANCE hInstance,LPCTSTR lpIconName); 加载图标
第一个参数值为NULL,则是设置系统默认几种类型的图标
Getlasterror可用于函数调用失败时获得拓展的错误信息。
WM_DESTROY消息
WM_DESTROY消息是另一个重要消息。这一个消息指示,Windows正在根据使用者的指示关闭窗口。该消息是使用者单击Close按钮或者在程序的系统菜单上选择 Close时发生的(在本章的后面,我们将详细讨论WM_DESTROY消息是如何生效的)。
HELLOWIN通过呼叫PostQuitMessage以标准方式响应WM_DESTROY消息:
PostQuitMessage (0) ;
该函数在程序的消息队列中插入一个WM_QUIT消息。前面提到过,GetMessage对于除了WM_QUIT之外的从消息队列中取出的所有消息都传回非0值。而当GetMessage得到一个WM_QUIT消息时,它传回0。这将导致WinMain退出消息循环,并终止程序。然后程序执行下面的叙述:
return msg.wParam ;
结构的wParam字段是传递给PostQuitMessage函数的值(通常是0)。然后return叙述将退出WinMain并终止程序。
第四章
程序使用InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息。
窗口消息处理程序可以通过呼叫InvalidateRect使显示区域内的矩形无效。如果消息队列中已经包含一个WM_PAINT消息,Windows将计算出新的无效矩形。否则,它将一个新的WM_PAINT消息放入消息队列中。在接收到WM_PAINT消息时,窗口消息处理程序可以取得无效矩形的坐标(我们马上就会看到这一点)。通过呼叫GetUpdateRect,可以在任何时候取得这些坐标。
在处理WM_PAINT消息处理期间,窗口消息处理程序在呼叫了BeginPaint之后,整个显示区域即变为有效。程序也可以通过呼叫ValidateRect函数使显示区域内的任意矩形区域变为有效。如果这呼叫具有令整个无效区域变为有效的效果,则目前队列中的任何WM_PAINT消息都将被删除。
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 得到白色画刷
要使用GetTextMetrics函数,需要先定义一个结构变量(通常称为tm):
TEXTMETRIC tm ;
在需要确定文字大小时,先取得设备内容句柄,再呼叫GetTextMetrics:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
ReleaseDC (hwnd, hdc) ;
此后,您就可以查看文字尺寸结构中的值,并有可能保存其中的一些以备将来使用。
下面是取得系统字体的字符宽度和高度的WM_CREATE程序代码:
case WM_CREATE:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC (hwnd, hdc) ;
return 0 ;
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ; //得到大小写字母的平均宽度
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC (hwnd, hdc) ;
UINT SetTextAlign( HDC hdc,UINT fMode);
该函数为指定设备环境设置文字对齐标志。
caseWM_SIZE: // WM_SIZE传回客户区的尺寸
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
在许多Windows程序中,WM_SIZE消息必然跟着一个WM_PAINT消息。为什么呢?因为在我们定义窗口类别时指定窗口类别样式为:
CS_HREDRAW | CS_VREDRAW
很容易在应用程序中包含水平或者垂直的滚动条,程序写作者只需要在CreateWindow的第三个参数中包括窗口样式(WS)标识符WS_VSCROLL(垂直卷动)和/或WS_HSCROLL(水平卷动)即可。这些卷动列通常放在窗口的右部和底部,伸展为显示区域的整个长度或宽度。显示区域不包含卷动列所占据的空间。对于特定的显示驱动程序和显示分辨率,垂直卷动列的宽度和水平卷动列的高度是恒定的。如果需要这些值,可以使用GetSystemMetrics呼叫来取得(如前面的程序那样)。
滚动条的范围和位置
SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ;
BOOL SetScrollRange( HWND hWnd, // 窗口句柄
int nBar, // 滚动条类型
int nMinPos, // 滚动条的最小位置
int nMaxPos, // 滚动条的最大位置
BOOL bRedraw // 重绘标志 );
int SetScrollPos(HWND hWnd, // 窗体句柄
int nBar, // 滚动条
int nPos, // 滚动条的新位置
BOOL bRedraw // 重绘标志 );
为了给使用者提供回馈,Windows在您用鼠标拖动卷动方块时移动它,同时您的程序会收到SB_THUMBTRACK消息。然而,如果不通过呼叫SetScrollPos来处理SB_THUMBTRACK或SB_THUMBPOSITION消息,在使用者释放鼠标键后,卷动方块会迅速跳回原来的位置。
程序能够处理SB_THUMBTRACK或SB_THUMBPOSITION消息,但一般不同时处理两者。如果处理SB_THUMBTRACK消息,在使用者拖动卷动方块时您需要移动显示区域的内容。而如果处理SB_THUMBPOSITION消息,则只需在使用者停止拖动卷动方块时移动显示区域的内容。处理SB_THUMBTRACK消息更好一些(但更困难),对于某些型态的数据,您的程序可能很难跟上产生的消息。
如果您希望立即更新无效区域,可以在呼叫InvalidateRect之后呼叫UpdateWindow:
建立更好的滚动
Win32 API介绍的两个滚动条函数称作SetScrollInfo和GetScrollInfo。这些函数可以完成以前函数的全部功能,并增加了两个新特性。
SetScrollInfo (hwnd, iBar, &si, bRedraw) ;
GetScrollInfo (hwnd, iBar, &si) ;
在呼叫SetScrollInfo或GetScrollInfo之前,必须将cbSize字段设定为结构的大小:
si.cbSize = sizeof (SCROLLINFO) ;
第五章
取得设备内容句柄
最常用的取得并释放设备内容句柄的方法是,在处理WM_PAINT消息时,使用BeginPaint和EndPaint呼叫:
hdc = BeginPaint (hwnd, &ps) ;
其它行程序
EndPaint (hwnd, &ps) ;
变量ps是型态为PAINTSTRUCT的结构,该结构的hdc字段是BeginPaint传回的设备内容句柄。 PAINTSTRUCT结构又包含一个名为rcPaint的RECT(矩形)结构,rcPaint定义一个包围窗口显示区域无效范围的矩形。使用从BeginPaint获得的设备内容句柄,只能在这个区域内绘图。BeginPaint呼叫使该区域有效。
Windows程序还可以在处理非WM_PAINT消息时取得设备内容句柄:
hdc = GetDC (hwnd) ;
其它行程序
ReleaseDC (hwnd, hdc) ;
Windows程序还可以取得适用于整个窗口(而不仅限于窗口的显示区域)的设备内容句柄:
hdc = GetWindowDC (hwnd) ;
其它行程序
ReleaseDC (hwnd, hdc) ;
这个设备内容除了显示区域之外,还包括窗口的标题列、菜单、滚动条和框架(frame)。GetWindowDC函数很少使用,如果想尝试用一用它,则必须拦截处理WM_NCPAINT消息,Windows使用该消息在窗口的非显示区域上绘图。
取得设备内容句柄的另一个更通用的函数是CreateDC:
hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData) ;
其它行程序
DeleteDC (hdc) ;
例如,您可以通过下面的呼叫来取得整个屏幕的设备内容句柄:
hdc = CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
取得设备内容信息
一个设备内容通常是指一个实际显示设备,如视讯显示器和打印机。通常,您需要取得有关该设备的信息,包括显示器的大小(单位为图素或者实际长度单位)和色彩显示能力。您可以通过呼叫GetDeviceCaps(「取得设备功能」)函数来取得这些信息:
iValue = GetDeviceCaps (hdc, iIndex) ;
某些情况下,您可能想改变某些设备内容属性,用改变后的属性进行绘图,然后恢复原来的设备内容。要简化这一过程,可以通过如下呼叫来保存设备内容的状态:
idSaved = SaveDC (hdc) ;
现在,可以改变一些属性,在想要回到呼叫SaveDC前存在的设备内容时,呼叫:
RestoreDC (hdc, idSaved) ;
SetPixel (hdc, x, y, crColor) ;
GetPixel函数传回指定坐标处的图素颜色:
crColor = GetPixel (hdc, x, y) ;
画一条直线,必须呼叫两个函数。第一个函数指定了线的开始点,第二个函数指定了线的终点:
MoveToEx (hdc, xBeg, yBeg, NULL) ;
LineTo (hdc, xEnd, yEnd) ;
如果您需要目前位置,就可以通过以下呼叫获得:
GetCurrentPositionEx (hdc, &pt) ;
当您要将数组中的点连接成线时,使用Polyline函数要简单得多。下面这条叙述画出与上面一段程序代码相同的矩形:
POINT apt[5] = { 100, 100, 200, 100, 200, 200, 100, 200, 100, 100 } ;
注意,最后一个点与第一个点相同。现在,只需要使用MoveToEx移到第一个点,并对后面的点使用LineTo:
Polyline (hdc, apt, 5) ;
MoveToEx (hdc, apt[0].x, apt[0].y, NULL) ;
PolylineTo (hdc, apt + 1, 4) ;
PolylineTo有些不同,这个函数使用目前位置作为开始点,并将目前位置设定为最后一根线的终点。
边界框函数
问题在于,Rectangle、Ellipse、RoundRect、Chord和Pie函数严格来说不是画线函数。没错,这些函数是在画线,但它们同时又填入画刷填入一个封闭区域。
这些函数中最简单的就是画一个矩形:
您知道了如何画矩形,也就知道了如何画椭圆,因为它们使用的参数都是相同的:
Ellipse (hdc, xLeft, yTop, xRight, yBottom) ;
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
画圆角矩形的函数使用与函数Rectangle及Ellipse函数相同的边界框,还包含另外两个参数:
RoundRect (hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse) ;
Arc、Chord和Pie函数都只要相同的参数:
Arc(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
Chord (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
Pie(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
在Windows 98中,您不需要知道这些公式。要画一条或多条连接的贝塞尔曲线,只需呼叫:
PolyBezier (hdc, apt, iCount) ; 或PolyBezierTo (hdc, apt, iCount) ;
使用现有画笔(Stock Pens)
HPEN hPen ;
hPen = GetStockObject (WHITE_PEN) ;
SelectObject (hdc, hPen) ;
SelectObject的传回值是此呼叫前设备内容中的画笔句柄。如果启动一个新的设备内容并呼叫
hPen = SelectObject (hdc, GetStockobject (WHITE_PEN)) ;
画笔的建立、选择和删除
尽管使用现有画笔非常方便,但却受限于实心的黑画笔、实心的白画笔或者没有画笔这三种情况。如果想得到更丰富多彩的效果,就必须建立自己的画笔。
这一过程通常是:使用函数CreatePen或CreatePenIndirect建立一个「逻辑画笔」,这仅仅是对画笔的描述。这些函数传回逻辑画笔的句柄;然后,呼叫SelectObject将画笔选进设备内容。
CreatePen函数的语法形如:
hPen = CreatePen (iPenStyle, iWidth, crColor) ;
要使用CreatePenIndirect,首先定义一个LOGPEN型态的结构:
LOGPEN logpen ;
hPen = CreatePenIndirect (&logpen) ;
您可以通过如下呼叫来改变Windows用来填入空隙的背景色
SetBkColor (hdc, crColor) ;
通过将背景模式转换为TRANSPARENT,可以阻止Windows填入空隙:
SetBkMode (hdc, TRANSPARENT) ;
此后,Windows将忽略背景色,并且不填入空隙,可以通过呼叫GetBkMode来取得目前背景模式(TRANSPARENT或者OPAQUE)。
绘图方式
可以通过以下呼叫在设备内容中设定新的绘图模式:
SetROP2 (hdc, iDrawMode) ;
iDrawMode参数是表中「绘图模式」一栏中给出的值之一。您可以用函数:
iDrawMode = GetROP2 (hdc) ;
如果您想画一个没有边界框的图形,可以将NULL_PEN选进设备内容:
SelectObject (hdc, GetStockObject (NULL_PEN)) ;
如果您想画出图形的边界框,但不填入内部,则将NULL_BRUSH选进设备内容:
SelectObject (hdc, GetStockobject (NULL_BRUSH) ;
对于Polygon和PolyPolygon函数,Windows使用定义在设备内容中的目前画刷来填入这个带边界的区域。至于填入内部的方式,则取决于多边形填入方式,您可以用SetPolyFillMode函数来设定:
SetPolyFillMode (hdc, iMode) ;
FillRect (hdc, &rect, hBrush) ;
FrameRect (hdc, &rect, hBrush) ; I
nvertRect (hdc, &rect) ;
在这些函数中,rect参数是一个RECT型态的结构,它包含有4个字段:left、top、right和bottom。这个结构中的坐标被当作逻辑坐标。
FillRect用指定画刷来填入矩形(直到但不包含right和bottom坐标),该函数不需要先将画刷选进设备内容。
FrameRect使用画刷画矩形框,但是不填入矩形。使用画刷画矩形看起来有点奇怪,因为对于我们所介绍过的函数(如Rectangle),其边线都是用目前画笔绘制的。FrameRect允许使用者画一个不一定为纯色的矩形框。该边界框为一个逻辑单位元宽。如果逻辑单位大于设备单位,则边界框将会为2个图素宽或者更宽。
InvertRect将矩形中所有图素翻转,1转换成0,0转换为1,该函数将白色区域转变成黑色,黑色区域转变为白色,绿色区域转变成洋红色。
但是,通过呼叫SetRect函数,只需要一道叙述就可以得到同样的结果:
SetRect (&rect, xLeft, yTop, xRight, yBottom) ;
在您想要做以下事情之一时,可以很方便地选用其它8个函数:
· 将矩形沿x轴和y轴移动几个单元:
OffsetRect (&rect, x, y) ;
· 增减矩形的尺寸:
InflateRect (&rect, x, y) ;
· 矩形各字段设定为0:
SetRectEmpty (&rect) ;
· 将矩形复制给另一个矩形:
CopyRect (&DestRect, &SrcRect) ;
· 取得两个矩形的交集:
IntersectRect (&DestRect, &SrcRect1, &SrcRect2) ;
· 取得两个矩形的联集:
UnionRect (&DestRect, &SrcRect1, &SrcRect2) ;
· 确定矩形是否为空:
bEmpty = IsRectEmpty (&rect) ;
· 确定点是否在矩形内:
bInRect = PtInRect (&rect, point) ;
PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) ;
前面的四个参数(一个指向MSG结构的指针、一个窗口句柄、两个值指示消息范围)与GetMessage的参数相同。将第二、三、四个参数设定为NULL或0时,表明我们想让PeekMessage传回程序中所有窗口的所有消息。如果要将消息从消息队列中删除,则将PeekMessage的最后一个参数设定为PM_REMOVE。如果您不希望删除消息,那么您可以将这个参数设定为PM_NOREMOVE。
while (TRUE)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else
{
// 完成某些工作的其它行程序
}
}
return msg.wParam ;
本文出自 “不曾远去” 博客,谢绝转载!