📄 见招拆招《windows程序设计》(八) .txt
字号:
见招拆招《Windows程序设计》(八)
作者:Zoologist 于2008-6-16上传
--------------------------------------------------------------------------------
子窗口控件
回忆前面介绍过的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程序设计的文件在两个地方讨论了子窗口控件:首先是,简单的常用控件。这些子窗口包括按钮(其中包括复选框的单选按钮)、静态控件(例如文字卷标)、编辑方块(您可以在此编辑一行或多行文字)、卷动列、清单方块和下拉式清单方块。除下拉式清单方块以外,在Windows 1.0中就包括了这些控件。这部分的Windows文件还包括Rich Text文字编辑控件,它与编辑方块相似,但还允许编辑不同字体与样式的格式化文字,以及桌面应用工具列。
相对于「常用控件」,还有一些神秘的特殊控件。本章不讨论常用控件,但它们将出现在本系列文章的其它部分。在这部分的Windows文件中,很容易找到您想从别的Windows应用程序中应用到您自己的应用程序里头那些部分信息。
按钮类别
下面我们将通过叫做BTNLOOK(「button look」)的程序来开始介绍按钮窗口类别,如程序9-1所示。BTNLOOK建立10个子窗口按钮控件,每个控件对应一个标准的按钮样式,因此共有10种标准按钮样式。
程序9-1 BTNLOOK
BTNLOOK.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
NUM equ (buttonEnd - button) /4 /2
.DATA
szAppName db "BtnLook",0
szBtn db "button",0
szDraw db "WM_DRAWITEM",0
szCom db "WM_COMMAND",0
szTop db "message wParam lParam",0
szUnd db "_______ ______ ______",0
szFormat db "%-16s%04X-%04X %04X-%04X",0
szBtnStyle01 db "PUSHBUTTON",0
szBtnStyle02 db "DEFPUSHBUTTON",0
szBtnStyle03 db "CHECKBOX",0
szBtnStyle04 db "AUTOCHECKBOX",0
szBtnStyle05 db "RADIOBUTTON",0
szBtnStyle06 db "3STATE",0
szBtnStyle07 db "AUTO3STATE",0
szBtnStyle08 db "GROUPBOX",0
szBtnStyle09 db "AUTORADIO",0
szBtnStyle10 db "OWNERDRAW",0
button dd BS_PUSHBUTTON, offset szBtnStyle01
dd BS_DEFPUSHBUTTON, offset szBtnStyle02
dd BS_CHECKBOX, offset szBtnStyle03
dd BS_AUTOCHECKBOX, offset szBtnStyle04
dd BS_RADIOBUTTON, offset szBtnStyle05
dd BS_3STATE, offset szBtnStyle06
dd BS_AUTO3STATE, offset szBtnStyle07
dd BS_GROUPBOX, offset szBtnStyle08
dd BS_AUTORADIOBUTTON, offset szBtnStyle09
dd BS_OWNERDRAW, offset szBtnStyle10
buttonEnd label DWORD
.DATA?
hInstance dd ?
hwndButton HWND NUM dup(?)
rect RECT <?>
cxChar dd ?
cyChar dd ?
.CODE
START:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,0
WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,iCmdShow:DWORD
LOCAL wndclass :WNDCLASSEX
LOCAL msg :MSG
local hWnd :HWND
mov wndclass.cbSize,sizeof WNDCLASSEX
mov wndclass.style,CS_HREDRAW or CS_VREDRAW
mov wndclass.lpfnWndProc,offset WndProc
mov wndclass.cbClsExtra,0
mov wndclass.cbWndExtra,0
push hInst
pop wndclass.hInstance
invoke LoadIcon,NULL,IDI_APPLICATION
mov wndclass.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wndclass.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov wndclass.hbrBackground,EAX
mov wndclass.lpszMenuName,NULL
mov wndclass.lpszClassName,offset szAppName
mov wndclass.hIconSm,0
invoke RegisterClassEx, ADDR wndclass
.if (EAX==0)
invoke MessageBox,NULL,CTXT("This program requires Windows NT!"),addr szAppName,MB_ICONERROR
ret
.endif
invoke CreateWindowEx,
NULL,
ADDR szAppName, ;window class name
CTXT("Button Look"), ;window caption
WS_OVERLAPPEDWINDOW, ;window style
CW_USEDEFAULT, ;initial x position
CW_USEDEFAULT, ;initial y position
CW_USEDEFAULT, ;initial x size
CW_USEDEFAULT, ;initial y size
NULL, ;parent window handle
NULL, ;window menu handle
hInstance, ;program instance handle
NULL ;creation parameters
mov hWnd,eax
invoke ShowWindow,hWnd,iCmdShow
invoke UpdateWindow,hWnd
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hwnd:DWORD,uMsg:DWORD,wParam :DWORD,lParam :DWORD
LOCAL szBuffer[100] :BYTE
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL i :DWORD
.if uMsg==WM_CREATE
invoke GetDialogBaseUnits ;cxChar = LOWORD (GetDialogBaseUnits ())
and eax,0FFFFh
mov cxChar,eax
invoke GetDialogBaseUnits
shr eax,16
mov cyChar,eax ;cyChar = HIWORD (GetDialogBaseUnits ())
;LPCREATESTRUCT不是结构,只是一个指向结构CREATESTRUCT的指针.以下是该结构的信息:
;The CREATESTRUCT structure defines the initialization parameters passed to the window procedure of an application.
;typedef struct tagCREATESTRUCT { // cs
; LPVOID lpCreateParams;
; HINSTANCE hInstance;
; HMENU hMenu;
; HWND hwndParent;
; int cy;
; int cx;
; int y;
; int x;
; LONG style;
; LPCTSTR lpszName;
; LPCTSTR lpszClass;
; DWORD dwExStyle;
;} CREATESTRUCT;
;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) ;
mov i,0
nexti:
push NULL
mov esi,lParam
mov eax,[esi+4]
push eax
push i
push hwnd
mov eax,cyChar
mov ecx,7
mul ecx
shr eax,2
push eax
mov eax,cxChar
mov ecx,20
mul ecx
push eax
mov eax,i
shl eax,1
inc eax
mov ecx,cyChar
mul ecx
push eax
push cxChar
lea esi,button
mov eax,i
shl eax,3
mov ebx,eax
mov eax,button[ebx]
or eax,WS_CHILD
or eax,WS_VISIBLE
push eax
mov eax,button[ebx+4]
push eax
lea eax,szBtn
push eax
push NULL
call CreateWindowEx
lea esi,button
mov ebx,i
shl ebx,2
mov hwndButton[ebx],eax
inc i
mov eax,i
cmp eax,NUM
jl nexti
xor eax,eax
ret
.elseif uMsg == WM_SIZE
mov eax,cxChar
mov ecx,24
mul ecx
mov rect.left,eax
mov eax,cyChar
shl eax,1
mov rect.top,eax
mov eax,lParam
and eax,0FFFFh
mov rect.right,eax
mov eax,lParam
shr eax,16
mov rect.bottom,eax
xor eax,eax
ret
.elseif uMsg == WM_PAINT
invoke InvalidateRect,hwnd,addr rect, TRUE
invoke BeginPaint,hwnd,addr ps
invoke GetStockObject,SYSTEM_FIXED_FONT
invoke SelectObject,hdc,eax
invoke SetBkMode,hdc, TRANSPARENT
;TextOut (hdc, 24 * cxChar, cyChar, szTop, lstrlen (szTop)) ;
invoke lstrlen,addr szTop
push eax
lea eax,szTop
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -