📄 9. 子窗口控件.txt
字号:
子窗口控件
智能中国——游戏组 整理编译
--------------------------------------------------------------------------------
回忆第七章的CHECKER程序。这些程序显示了矩形网格。当您在一个矩形中按下鼠标按键时,该程序就画一个x;如果您再按一次鼠标按键,那么x就消失。虽然这个程序的CHECKER1和CHECKER2版本只使用一个主窗口,但CHECKER3版本却为每个矩形使用一个子窗口。这些矩形由一个叫做ChildProc的独立窗口消息处理程序维护。
如果有必要,无论矩形是否被选中,都可以给ChildProc增加一种向其父窗口消息处理程序(WndProc)发送消息的手段。通过呼叫GetParent,子窗口消息处理程序能确定其父窗口的窗口句柄:
hwndParent = GetParent (hwnd) ;
其中,hwnd是子窗口的窗口句柄。它可以向其父窗口消息处理程序发送消息:
SendMessage (hwndParent, message, wParam, lParam) ;
那么message应该设定为什么呢?您可以随意地设定,数值大小可以与WM_USER相同或更大,这些数字代表和预先定义的WM_ 消息不冲突的消息。也许对这个消息,子窗口可以将wParam设定为它的子窗口ID。如果在该子窗口单击,那么lParam可以被设为1;如果未在该子窗口上单击,那么lParam将被设为0。这是处理方式的一种选择。
事实上,这是在建立一个「子窗口控件」。当子窗口的状态改变时,子窗口处理鼠标和键盘消息并通知父窗口。使用这种方法,子窗口就变成了其父窗口的高阶输入设备。它将与自己在屏幕上的图形外观相应的处理,对使用者输入的响应以及在发生重要的输入事件时通知另一个窗口的方法给封装起来。
虽然您可以建立自己的子窗口控件,但是也可以利用一些预先定义的窗口类别(和窗口消息处理程序)来建立标准的子窗口控件,您一定在别的Windows程序中看到过这些控件。这些控件采用的形式有:按钮、复选框、编辑方块、清单方块、下拉式清单方块、字符串卷标和卷动列。例如,如果想在您的电子表格程序的某个角落放置一个标有「Recalculate」的按钮,那么您可以通过呼叫CreateWindow来建立这个按钮。您不必担心鼠标操作、按钮显示操作或按下该按钮时的自动闪烁操作,这些是由Windows内部完成的。您所要做的只是拦截WM_COMMAND消息-当按钮被按下时,它通过这一消息通知您的窗口消息处理程序。真的这样简单吗?是的,一点也没错。
子窗口控件在对话框中最常用。在第十一章中您将会看到,子窗口控件的位置和尺寸,是在范例程序的资源描述叙述中的对话框模板里定义的。但是,您也可以使用预先定义的,在普通窗口显示区域里的子窗口控件。您可以呼叫一次CreateWindow来建立一个子窗口,并通过呼叫MoveWindow来调整子窗口的位置和尺寸。父窗口消息处理程序向子窗口控件发送消息,子窗口控件向父窗口消息处理程序传回消息。
在建立普通窗口时,首先定义窗口类别,并使用RegisterClass将其注册到Windows中,然后用CreateWindow命令依据该窗口类别建立一个普通窗口,从第三章开始,我们就是这么做的。但是,当您使用预先定义的某个控件时,不必为子窗口注册窗口类别,窗口类别已经存在于Windows之中,并且有一个预先定义的名字。您只需在CreateWindow中把它们用作窗口类别参数。CreateWindow中的窗口样式参数准确地定义了子窗口控件的外形和功能。Windows内建了处理发送给依据这些窗口类别建立的子窗口消息的窗口消息处理程序。
直接在您的窗口上使用子窗口控件完成某些任务,这些任务的层次低于在对话框中使用子窗口控件所要求的层次。这里,对话框管理器在您的程序和控件之间增加一个隔离层。值得一提的,您可能会发现在您的窗口上建立的子窗口控件,没有利用Tab键或方向键将输入焦点从一个控件移动到另一个控件的内部功能。子窗口控件能够获得输入焦点,但是获得后,它将不能把输入焦点传回给父窗口。这就是本章要解决的问题。
Windows程序设计的文件在两个地方讨论了子窗口控件:首先是,简单的常用控件,我们可以在/Platform SDK/User Interface Services/Controls的文件所描述的无数对话框中看到。这些子窗口包括按钮(其中包括复选框的单选按钮)、静态控件(例如文字卷标)、编辑方块(您可以在此编辑一行或多行文字)、卷动列、清单方块和下拉式清单方块。除下拉式清单方块以外,在Windows 1.0中就包括了这些控件。这部分的Windows文件还包括Rich Text文字编辑控件,它与编辑方块相似,但还允许编辑不同字体与样式的格式化文字,以及桌面应用工具列。
相对于「常用控件」,还有一些神秘的特殊控件。这些控件在/Platform SDK/User Interface Services/Shell and Common Controls/Common Controls描述。本章不讨论常用控件,但它们将出现在本书的其它部分。在这部分的Windows文件中,很容易找到您想从别的Windows应用程序中应用到您自己的应用程序里头那些部分信息。
按钮类别
下面我们将通过叫做BTNLOOK(「button look」)的程序来开始介绍按钮窗口类别,如程序9-1所示。BTNLOOK建立10个子窗口按钮控件,每个控件对应一个标准的按钮样式,因此共有10种标准按钮样式。
程序9-1 BTNLOOK
BTNLOOK.C
/*--------------------------------------------------------------------------
BTNLOOK.C -- Button Look Program
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include <windows.h>
struct
{
int iStyle ;
TCHAR * szText ;
}
button[] =
{
BS_PUSHBUTTON, TEXT ("PUSHBUTTON"),
BS_DEFPUSHBUTTON, TEXT ("DEFPUSHBUTTON"),
BS_CHECKBOX, TEXT ("CHECKBOX"),
BS_AUTOCHECKBOX, TEXT ("AUTOCHECKBOX"),
BS_RADIOBUTTON, TEXT ("RADIOBUTTON"),
BS_3STATE, TEXT ("3STATE"),
BS_AUTO3STATE, TEXT ("AUTO3STATE"),
BS_GROUPBOX, TEXT ("GROUPBOX"),
BS_AUTORADIOBUTTON, TEXT ("AUTORADIO"),
BS_OWNERDRAW, TEXT ("OWNERDRAW")
} ;
#define NUM (sizeof button / sizeof button[0])
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("BtnLook") ;
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 = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Button Look"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton[NUM] ;
static RECT rect ;
static TCHAR szTop[] = TEXT ("message wParam lParam"),
szUnd[] = TEXT ("_______ ______ ______"),
szFormat[] = TEXT ("%-16s%04X-%04X %04X-%04X"),
szBuffer[50] ;
static int cxChar, cyChar ;
HDC hdc ;
PAINTSTRUCT ps ;
int i ;
switch (message)
{
case WM_CREATE :
cxChar = LOWORD (GetDialogBaseUnits ()) ;
cyChar = HIWORD (GetDialogBaseUnits ()) ;
for (i = 0 ; i < NUM ; i++)
hwndButton[i] =CreateWindow ( TEXT("button"),button[i].szText,
WS_CHILD | WS_VISIBLE | button[i].iStyle,
cxChar, cyChar * (1 + 2 * i),
20 * cxChar, 7 * cyChar / 4,
hwnd, (HMENU) i,
((LPCREATESTRUCT) lParam)->hInstance, NULL) ;
return 0 ;
case WM_SIZE :
rect.left = 24 * cxChar ;
rect.top = 2 * cyChar ;
rect.right = LOWORD (lParam) ;
rect.bottom = HIWORD (lParam) ;
return 0 ;
case WM_PAINT :
InvalidateRect (hwnd, &rect, TRUE) ;
hdc = BeginPaint (hwnd, &ps) ;
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
SetBkMode (hdc, TRANSPARENT) ;
TextOut (hdc, 24 * cxChar, cyChar, szTop, lstrlen (szTop)) ;
TextOut (hdc, 24 * cxChar, cyChar, szUnd, lstrlen (szUnd)) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DRAWITEM :
case WM_COMMAND :
ScrollWindow (hwnd, 0, -cyChar, &rect, &rect) ;
hdc = GetDC (hwnd) ;
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
TextOut( hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),
szBuffer,
wsprintf (szBuffer, szFormat,
message == WM_DRAWITEM ? TEXT ("WM_DRAWITEM") :
TEXT ("WM_COMMAND"),
HIWORD (wParam), LOWORD (wParam),
HIWORD (lParam), LOWORD (lParam))) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -