?? 009.txt
字號:
第九課 子窗口控件
--------------------------------------------------------------------------------
本課中我們將探討控件,這些控件是我們程序主要的輸入輸出設(shè)備。
理論:
WINDOWS 提供了幾個預(yù)定義的窗口類以方便我們的使用。大多數(shù)時間內(nèi),我們把它們用在對話框中,所以我們一般就它們叫做子窗口控件。子窗口控件會自己處理消息,并在自己狀態(tài)發(fā)生改變時通知父窗口。這樣就大大地減輕了我們的編程工作,所以我們應(yīng)盡可能地利用它們。本課中我們把這些控件放在窗口中以簡化程序,但是大多數(shù)時間內(nèi)子窗口控件都是放在對話框中的。我們示例中演示的子窗口控件包括:按鈕、下拉菜單、檢查框、單選按鈕、編輯框等。使用子窗口控件時,先調(diào)用CreateWindow 或 CreateWindowEx。在這里由于WINDOWS 已經(jīng)注冊了這些子控件,所以無須我們再注冊。當然我們不能改變它們的類名稱。譬如:如果您想產(chǎn)生一個按鈕,在調(diào)用上述兩個函數(shù)時就必須指定類名為"button"。其他必須指定的參數(shù)還有父窗口的句柄和將要產(chǎn)生的子控件的ID號。子控件的ID號是用來標識子控件的,故也必須是唯一 的。子控件產(chǎn)生后,當其狀態(tài)改變時將會向父窗口發(fā)送消息。一般我們應(yīng)在父窗口的WM_CREATE消息中產(chǎn)生字控件。子控件向父窗口發(fā)送的消息是WM_COMMAND,并在傳遞的參數(shù)wPara的底位中包括控件的ID號,消息號在wParam的高位,lParam中則包括了子控件的窗口的句柄。各類控件有不同的消息代碼集,詳情請參見WIN32 API參考手冊。父窗口也可以通過調(diào)用函數(shù)SendMessage向子控件發(fā)送消息,其中第一個參數(shù)是子控件的窗口句柄,第二個參數(shù)是要發(fā)送的消息號,附加的參數(shù)可以在wParam和lParam中傳遞,其實只要知道了某個窗口的句柄就可以用該函數(shù)向其發(fā)送相關(guān)消息。所以產(chǎn)生了子窗口后必須處理WM_COMMAND消息以便可以接收到子控件的消息。
例子:
我們將產(chǎn)生一個窗口,在該窗口中有一個編輯框和一個按鈕。當您按下按鈕時 ,會彈出一個對話框其中顯示了您在編輯框中輸入的內(nèi)容。另外,該應(yīng)用程序還有一個菜單,其中有四個菜單項:
Say Hello -- 把一個字符串輸入編輯控件;
Clear Edit Box -- 清除編輯控件中的字符串;
Get Text -- 彈出對話框顯示編輯控件中的字符串;
Exit -- 退出應(yīng)用程序。
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "My First Button",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?) ; buffer to store the text retrieved from the edit box
.const
ButtonID equ 1 ; The control ID of the button control
EditID equ 2 ; The control ID of the edit control
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName, \
ADDR AppName, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT, CW_USEDEFAULT,\
300,200,NULL,NULL, hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,35,200,25,hWnd,8,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
分析:
我們現(xiàn)在開始分析,
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, \
ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT\
or ES_AUTOHSCROLL,\
50,35,200,25,hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,\
ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
我們在WM_CREATE中產(chǎn)生子控件,其中在函數(shù)CreateWindowEx中給子控件窗口一個WS_EX_CLIENTEDGE風格,它使得子控件窗口看上去邊界下凹,具有立體感。每一個子控件的類名都是預(yù)定義的,譬如:按鈕的預(yù)定義類名是"button",編輯框是"edit"。接下來的參數(shù)是窗口風格,除了通常的窗口風格外,每一個控件都有自己的擴展風格,譬如:按鈕類的擴展風格前面加有BS_,編輯框類則是:ES_,WIN32 API 參考中有所有的擴展風格的描述。注意:您在CreateWindowsEx函數(shù)中本來要傳遞菜單句柄的地方傳入子窗口空間的ID號不會有什么副作用,因為子窗口控件本身不能有菜單。產(chǎn)生控件后,我們保存它們的句柄,然后調(diào)用SetFocus把焦點設(shè)到編輯控件上以便用戶立即可以輸入。接下來的是如何處理控件發(fā)送的通知消息WM_COMMAND:
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
我們以前講過選擇菜單想也會發(fā)送WM_COMMAND 消息,那我們應(yīng)如何區(qū)分呢?看了下表您就會一目了然:
Low word of wParam High word of wParam lParam
Menu Menu ID 0 0
Control Control ID Notification code Child Window Handle
其中我們可以看到不能用wParam來區(qū)分,因為菜單和控件的ID號可能相同,而且子窗口空間的消息號也有可能為0。
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
您可以調(diào)用SetWindowText函數(shù)把一字符串繁縟到編輯控件中去,為了清0,傳入NULL值。SetWindowText是一個通用函數(shù),即可以用它來設(shè)定一個窗口的標題,也可以用它來改變一個按鈕上的文字。如果是要得到按鈕上的文字,則調(diào)用GetWindowText。
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
上面的片段是處理用戶按鈕事件的。他首先檢查wParam的高字節(jié)看是否是按鈕的ID 號,若是則檢查低字節(jié)看發(fā)送的消息號是否BN_CLICKED,該消息是在按鈕按下時發(fā)送的,如果一切都對,則轉(zhuǎn)入處理該消息,我們可以從處理消息IDM_GETTEXT處復(fù)制全部的代碼,但是更專業(yè)的辦法是在發(fā)送一條IDM_GETTEXT消息讓主窗口過程處理,這只要把傳送的消息設(shè)置為WM_COMMAND,再把wParam的低字節(jié)中設(shè)置為IDM_GETTEXT即可。這樣一來您的代碼就簡潔了許多,所以盡可能利用該技巧。最后,當然不是或有或無,必須在消息循環(huán)中調(diào)用函數(shù)TranslateMessage,因為您的應(yīng)用程序需要在編輯框中輸入可讀的文字。如果省略了該函數(shù),就不能在編輯框中輸入任何東西。
--------------------------------------------------------------------------------
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -