📄 9. 子窗口控件.txt
字号:
pt[2].x = 4 * cx / 8 ; pt[2].y = 5 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
pt[0].x = 1 * cx / 8 ; pt[0].y = 5 * cy / 8 ;
pt[1].x = 1 * cx / 8 ; pt[1].y = 3 * cy / 8 ;
pt[2].x = 3 * cx / 8 ; pt[2].y = 4 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
break ;
case ID_LARGER :
pt[0].x = 5 * cx / 8 ; pt[0].y = 3 * cy / 8 ;
pt[1].x = 3 * cx / 8 ; pt[1].y = 3 * cy / 8 ;
pt[2].x = 4 * cx / 8 ; pt[2].y = 1 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
pt[0].x = 5 * cx / 8 ; pt[0].y = 5 * cy / 8 ;
pt[1].x = 5 * cx / 8 ; pt[1].y = 3 * cy / 8 ;
pt[2].x = 7 * cx / 8 ; pt[2].y = 4 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
pt[0].x = 3 * cx / 8 ; pt[0].y = 5 * cy / 8 ;
pt[1].x = 5 * cx / 8 ; pt[1].y = 5 * cy / 8 ;
pt[2].x = 4 * cx / 8 ; pt[2].y = 7 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
pt[0].x = 3 * cx / 8 ; pt[0].y = 3 * cy / 8 ;
pt[1].x = 3 * cx / 8 ; pt[1].y = 5 * cy / 8 ;
pt[2].x = 1 * cx / 8 ; pt[2].y = 4 * cy / 8 ;
Triangle (pdis->hDC, pt) ;
break ;
}
// Invert the rectangle if the button is selected
if (pdis->itemState & ODS_SELECTED)
InvertRect (pdis->hDC, &pdis->rcItem) ;
// Draw a focus rectangle if the button has the focus
if (pdis->itemState & ODS_FOCUS)
{
pdis->rcItem.left += cx / 16 ;
pdis->rcItem.top += cy / 16 ;
pdis->rcItem.right -= cx / 16 ;
pdis->rcItem.bottom-= cy / 16 ;
DrawFocusRect (pdis->hDC, &pdis->rcItem) ;
}
return 0 ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
该程序在其显示区域的中央包含了两个按钮,如图9-2所示。左边的按钮有四个三角形指向按钮的中央,按下该按钮时,窗口的尺寸将缩小10%。右边的按钮有四个向外指的三角形,按下此按钮时,窗口的尺寸将增大10%。
如果您只需要在按钮中显示图标或位图,您可以用BS_ICON或BS_BITMAP样式,并用BM_SETIMAGE消息设定位图。但是,对于BS_OWNERDRAW样式的按钮,它允许完全自由地绘制按钮。
图9-2 OWNDRAW的屏幕显示
在处理WM_CREATE消息处理期间,OWNDRAW建立了两个BS_OWNERDRAW样式的按钮;按钮的宽度是系统字体的8倍,高度是系统字体的4倍(在使用预先定义好的位图绘制按钮时,这些尺寸在VGA上建立的按钮为64图素宽64图素高,知道这些数据将非常有用)。这些按钮尚未就定位,在处理WM_SIZE消息处理期间,通过呼叫MoveWindow函数,OWNDRAW将按钮位置放在显示区域的中心。
按下这些按钮时,它们就会产生WM_COMMAND消息。为了处理这些WM_COMMAND消息,OWNDRAW呼叫GetWindowRect,将整个窗口(不只是显示区域)的位置和尺寸存放在RECT(矩形)结构中,这个位置是相对于屏幕的。然后,根据按下的是左边还是右边的按钮,OWNDRAW调节这个矩形结构的各个字段值。程序再通过呼叫MoveWindow来重新确定位置和尺寸。这将产生另一个WM_SIZE消息,按钮被重新定位在显示区域的中央。
如果这是程序所做的全部处理,那么这完全可以,只不过按钮是不可见的。使用BS_OWNERDRAW样式建立的按钮会在需要重新着色的任何时候都向它的父窗口发送一个WM_DRAWITEM消息。这出现在以下几种情况中:当按钮被建立时,当按钮被按下或被放开时,当按钮得到或者失去输入焦点时,以及当按钮需要重新着色的任何时候。
在处理WM_DRAWITEM消息处理期间,lParam消息参数是指向型态DRAWITEMSTRUCT结构的指针,OWNDRAW程序将这个指针储存在pdis变量中,这个结构包含了画该按钮时程序所必需的消息(这个结构也可以让自绘清单方块和菜单使用)。对按钮而言非常重要的结构字段有hDC (按钮的设备内容)、rcItem(提供按钮尺寸的RECT结构)、CtlID(控件窗口ID)和itemState (它说明按钮是否被按下,或者按钮是否拥有输入焦点)。
呼叫FillRect用白色画刷抹掉按钮的内面,呼叫FrameRect在按钮的周围画上黑框,由此OWNDRAW便启动了WM_DRAWITEM处理过程。然后,通过呼叫Polygon,OWNDRAW在按钮上画出4个黑色实心的三角形。这是一般的情形。
如果按钮目前被按下,那么DRAWITEMSTRUCT的itemState字段中的某位将被设为1。您可以使用ODS_SELECTED常数来测试这些位。如果这些位被设立,那么OWNDRAW将通过呼叫InvertRect将按钮翻转为相反的颜色。如果按钮拥有输入焦点,那么itemState的ODS_FOCUS位将被设立。在这种情况下,OWNDRAW通过呼叫DrawFocusRect,在按钮的边界内画一个虚线的矩形。
在使用拥有者绘制按钮时,应该注意以下几个方面:Windows获得设备内容并将其作为DRAWITEMSTRUCT结构的一个字段。保持设备内容处于您找到它时所处的状态,任何被选进设备内容的GDI对象都必需被释放。另外,当心不要在定义按钮边界的矩形外面进行绘制。
静态类别
在CreateWindow函数中指定窗口类别为「static」,您就可以建立静态文字的子窗口控件。这些子窗口非常「文静」。它既不接收鼠标或键盘输入,也不向父窗口发送WM_COMMAND消息。
当您在静态子窗口上移动或者按下鼠标时,这个子窗口将拦截WM_NCHITTEST消息并将HTTRANSPARENT的值传回给Windows,这将使Windows向其下层窗口,通常是它的父窗口,发送相同的WM_NCHITTEST消息。父窗口常常将该消息传递给DefWindowProc,在这里,它被转换为显示区域的鼠标消息。
前六个静态窗口样式只简单地在子窗口的显示区域内画一个矩形或者边框。在下表的上部,「RECT」静态样式(左列)是填入图样的矩形样式;三个「FRAME」样式(右列)是没有填入图样的矩形轮廓:
SS_BLACKRECT
SS_GRAYRECT
SS_WHITERECT
SS_BLACKFRAME
SS_GRAYFRAME
SS_WHITEFRAME
「BLACK」、「GRAY」、「WHITE」并不意味着黑、灰和白色,这些颜色是由系统颜色决定的,如表9-4所示。
表9-4
静态控件
系统颜色
BLACK
COLOR_3DDKSHADOW
GRAY
COLOR_BTNSHADOW
WHITE
COLOR_BTNHIGHLIGHT
对这些样式,CreateWindow呼叫中的窗口文字字段被忽略。矩形的左上角开始于x位置坐标和y位置坐标,这些坐标都相对于父窗口。您也可以使用SS_ETCHEDHORZ、SS_ETCHEDVERT或者SS_ETCHEDFRAME ,采用灰色和白色建立一个形似阴影的边框。
静态类别也包括了三种文字样式:SS_LEFT、SS_RIGHT和SS_CENTER。它们建立左对齐、置右对齐和居中文字。文字在CreateWindow呼叫的窗口文字参数中给出,并且在以后可以用SetWindowText来改变它。当静态控件的窗口消息处理程序显示文字时,它使用DrawText函数以及DT_WORDBREAK、DT_NOCLIP和DT_EXPANDTABS参数。文字在子窗口的矩形内可以按文字进行换行。
这三种文字样式子窗口的背景通常为COLOR_BTNFACE,而文字本身是COLOR_WINDOWTEXT。在拦截WM_CTLCOLORSTATIC消息时,您可以通过呼叫SetTextColor来改变文字颜色,通过SetBkColor来改变背景颜色,并传回背景画刷句柄。后面的COLORS1程序展示了这一点。
最后,静态类别还包括了窗口样式SS_ICON和SS_USERITEM,但是当它们被用作子窗口控件时却没有任何意义。我们在讨论对话框时还要提及它们。
滚动条类别
我在第四章首次讨论了滚动条,也讨论了「窗口滚动条」和「滚动条控件」之间的一些区别。SYSMETS程序使用窗口滚动条,它出现在窗口的右边和底部。您可以在建立窗口时通过将标识符WS_VSCROLL、WS_HSCROLL或者两者都包含在窗口样式中,让窗口加上滚动条。现在我们准备建立一些滚动条控件,它们是能在父窗口的显示区域的任何地方出现的子窗口。您可以使用预先定义的窗口类别「scrollbar」以及两个滚动条样式SBS_VERT和SBS_HORZ中的一个来建立子窗口滚动条控件。
与按钮控件(以及将在后面讨论的编辑和清单方块控件)不同,滚动条控件不向父窗口发送WM_COMMAND消息,而是像窗口滚动条那样发送WM_VSCROLL和WM_HSCROLL消息。在处理卷动消息时,您可以通过lParam参数来区分窗口滚动条与滚动条控件。对子窗口滚动条其值为0,对于滚动条控件其值为滚动条窗口句柄。对窗口滚动条和滚动条控件来说,wParam参数的高字组和低字组的含义相同。
虽然窗口滚动条有固定的宽度,Windows使用CreateWindow呼叫中(或者在后面的MoveWindow呼叫中)给定的矩形尺寸来确定滚动条控件的尺寸。您可以建立细而长的滚动条控件,也可以建立短而粗的滚动条控件。
如果您想建立与窗口滚动条尺寸相同的滚动条控件,那么可以使用GetSystemMetrics取得水平滚动条的高度:
GetSystemMetrics (SM_CYHSCROLL) ;
或者垂直滚动条的宽度:
GetSystemMetrics (SM_CXVSCROLL) ;
根据Windows文件,滚动条窗样式标识符SBS_LEFTALIGN、SBS_RIGHTALIGN、SBS_TOP ALIGN和SBS_BOTTOMALIGN给出滚动条的标准尺寸,但是这些样式只在对话框中对滚动条有效。
对窗口滚动条,您可以使用同样的呼叫来建立滚动条控件的范围和位置:
SetScrollRange (hwndScroll, SB_CTL, iMin, iMax, bRedraw) ;
SetScrollPos (hwndScroll, SB_CTL, iPos, bRedraw) ;
SetScrollInfo (hwndScroll, SB_CTL, &si, bRedraw) ;
其区别在于:窗口滚动条将父窗口的句柄作为第一个参数,并且以SB_VERT或者SB_HORZ作为第二个参数。
令人吃惊的是,名为COLOR_SCROLLBAR的系统颜色不再用于滚动条。两端的按钮和小方块的颜色由COLOR_BTNFACE、COLOR_BTNHILIGHT、COLOR_BTNSHADOW、COLOR_BTNTEXT (用于小箭头)、COLOR_DKSHADOW和COLOR_BTNLIGHT决定。两端按钮之间区域的颜色由COLOR_BTNFACE和COLOR_BTNHIGHLIGHT决定。
如果您拦截了WM_CTLCOLORSCROLLBAR消息,那么可以在消息处理中传回画刷以取代该颜色。让我们来试一下。
COLORS1程序
为了解滚动条和静态子窗口的一些用法-也为了深入了解颜色-我们将使用COLORS1程序,如程序9-3所示。COLORS1在显示区域的左半部显示三种滚动条,并分别标以「Red」、「 Green」和「Blue」。当您挪动滚动条时,显示区域的右半部将变为三种原色混合而成的合成色,三种原色的数值显示在三个滚动条的下面。
程序9-3 COLORS1
COLORS1.C
/*------------------------------------------------------------------------
COLORS1.C -- Colors Using Scroll Bars
(c) Charles Petzold, 1998
-------------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM) ;
int idFocus ;
WNDPROC OldScroll[3] ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Colors1") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = CreateSolidBrush (0) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -