子視窗控制元件(轉)

heying1229發表於2007-07-28
子視窗控制元件:

  本課中我們將探討控制元件,這些控制元件是我們程式主要的輸入輸出裝置。
理論:
WINDOWS 提供了幾個預定義的視窗類以方便我們的使用。大多數時間內,我們把它們用在對話方塊中,所以我們一般就它們叫做子視窗控制元件。子視窗控制元件會自己處理訊息,並在自己狀態發生改變時通知父視窗。這樣就大大地減輕了我們的程式設計工作,所以我們應儘可能地利用它們。本課中我們把這些控制元件放在視窗中以簡化程式,但是大多數時間內子視窗控制元件都是放在對話方塊中的。我們示例中演示的子視窗控制元件包括:按鈕、下拉選單、檢查框、單選按鈕、編輯框等。使用子視窗控制元件時,先呼叫CreateWindow 或 CreateWindowEx。在這裡由於WINDOWS 已經註冊了這些子控制元件,所以無須我們再註冊。當然我們不能改變它們的類名稱。譬如:如果您想產生一個按鈕,在呼叫上述兩個函式時就必須指定類名為"button"。其他必須指定的引數還有父視窗的控制程式碼和將要產生的子控制元件的ID號。子控制元件的ID號是用來標識子控制元件的,故也必須是唯一 的。子控制元件產生後,當其狀態改變時將會向父視窗傳送訊息。一般我們應在父視窗的WM_CREATE訊息中產生字控制元件。子控制元件向父視窗傳送的訊息是WM_COMMAND,並在傳遞的引數wPara的底位中包括控制元件的ID號,訊息號在wParam的高位,lParam中則包括了子控制元件的視窗的控制程式碼。各類控制元件有不同的訊息程式碼集,詳情請參見WIN32 API參考手冊。父視窗也可以透過呼叫函式SendMessage向子控制元件傳送訊息,其中第一個引數是子控制元件的視窗控制程式碼,第二個引數是要傳送的訊息號,附加的引數可以在wParam和lParam中傳遞,其實只要知道了某個視窗的控制程式碼就可以用該函式向其傳送相關訊息。所以產生了子視窗後必須處理WM_COMMAND訊息以便可以接收到子控制元件的訊息。

例子:
我們將產生一個視窗,在該視窗中有一個編輯框和一個按鈕。當您按下按鈕時 ,會彈出一個對話方塊其中顯示了您在編輯框中輸入的內容。另外,該應用程式還有一個選單,其中有四個選單項:
Say Hello -- 把一個字串輸入編輯控制元件;
Clear Edit Box -- 清除編輯控制元件中的字串;
Get Text -- 彈出對話方塊顯示編輯控制元件中的字串;
Exit -- 退出應用程式。
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.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

分析:
我們現在開始分析,
.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中產生子控制元件,其中在函式CreateWindowEx中給子控制元件視窗一個WS_EX_CLIENTEDGE風格,它使得子控制元件視窗看上去邊界下凹,具有立體感。每一個子控制元件的類名都是預定義的,譬如:按鈕的預定義類名是"button",編輯框是"edit"。接下來的引數是視窗風格,除了通常的視窗風格外,每一個控制元件都有自己的擴充套件風格,譬如:按鈕類的擴充套件風格前面加有BS_,編輯框類則是:ES_,WIN32 API 參考中有所有的擴充套件風格的描述。注意:您在CreateWindowsEx函式中本來要傳遞選單控制程式碼的地方傳入子視窗空間的ID號不會有什麼副作用,因為子視窗控制元件本身不能有選單。產生控制元件後,我們儲存它們的控制程式碼,然後呼叫SetFocus把焦點設到編輯控制元件上以便使用者立即可以輸入。接下來的是如何處理控制元件傳送的通知訊息WM_COMMAND:
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0

我們以前講過選擇選單想也會傳送WM_COMMAND 訊息,那我們應如何區分呢?看了下表您就會一目瞭然:

Low word of wParam High word of wParam lParam
Menu Menu ID 0 0
Control Control ID Notification code Child Window Handle

其中我們可以看到不能用wParam來區分,因為選單和控制元件的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

您可以呼叫SetWindowText函式把一字串繁縟到編輯控制元件中去,為了清0,傳入NULL值。SetWindowText是一個通用函式,即可以用它來設定一個視窗的標題,也可以用它來改變一個按鈕上的文字。如果是要得到按鈕上的文字,則呼叫GetWindowText。

.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF

上面的片段是處理使用者按鈕事件的。他首先檢查wParam的高位元組看是否是按鈕的ID 號,若是則檢查低位元組看傳送的訊息號是否BN_CLICKED,該訊息是在按鈕按下時傳送的,如果一切都對,則轉入處理該訊息,我們可以從處理訊息IDM_GETTEXT處複製全部的程式碼,但是更專業的辦法是在傳送一條IDM_GETTEXT訊息讓主視窗過程處理,這隻要把傳送的訊息設定為WM_COMMAND,再把wParam的低位元組中設定為IDM_GETTEXT即可。這樣一來您的程式碼就簡潔了許多,所以儘可能利用該技巧。最後,當然不是或有或無,必須在訊息迴圈中呼叫函式TranslateMessage,因為您的應用程式需要在編輯框中輸入可讀的文字。如果省略了該函式,就不能在編輯框中輸入任何東西。

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10172717/viewspace-928722/,如需轉載,請註明出處,否則將追究法律責任。

相關文章