?? 010.txt
字號:
第十課 以對話框為主要界面的應(yīng)用程序
--------------------------------------------------------------------------------
現(xiàn)在我們開始學(xué)習(xí)一些有關(guān)GUI編程的有趣的部分, 即:以對話框為主要界面的應(yīng)用程序。我們將分兩課來講述這一過程
理論:
如果您仔細關(guān)注過前一個程序就會發(fā)現(xiàn):您無法按TAB鍵從一個子窗口控件跳到另一個子窗口控件,要想轉(zhuǎn)移的話只有 用鼠標(biāo)一下一下地去點擊。對用戶來說這是不友好的。另一件事是如果您象前一課中那樣把主窗口的背景色從白色改成 灰色,為了子窗口控件無縫地作相應(yīng)地改變,您必須細分類所有子窗口。 造成上述諸多不便的原因是子窗口控件本來是為對話框而設(shè)計的,象子窗口控件的背景色是灰色的,而對話框的背景色也是 灰色的,這樣它們本來就相互協(xié)調(diào)了,而無須程序員加入其他的處理。 在我們深入討論對話框前我們必須知道何謂對話框。一個對話框其實是有很多的子窗口控件的一個窗口,WINDOWS在對話框 內(nèi)部有一個管理程序,由其來處理象按下TAB鍵則輸入焦點從一個子窗口空間條到另一個子窗口控件、按下ENTER鍵等于在當(dāng) 前具有輸入焦點的子窗口控件上點擊了鼠標(biāo) 等等這些雜事,這樣程序員就可以集中精力于他們的邏輯事務(wù)了。對話框主要用 作輸入輸出接口,人們無須知道它們內(nèi)部的工作原理,而只要知道如何和他們進行交互就可以了。這也是面向?qū)ο笤O(shè)計中的 所謂信息隱藏。只要這個黑盒子中的實現(xiàn)足夠完美,我們就可以放心地使用,當(dāng)然我們必須強調(diào)的是“黑盒子”必須完美。 WIN32 API 內(nèi)部 的實現(xiàn)即是一個“黑盒子”。 噢,好象我們的討論有些走題,現(xiàn)在讓我們回到正題來,對話框的設(shè)計是為了減少程序員的工作量的,一般您如果在窗口中 自己放一個子窗口控件您就必須自己處理其中的按鍵邏輯和細分類它的窗口過程。如果您把它放到對話框中,則這些雜事 對話框會自己處理,您只要知道如何獲得用戶輸入的數(shù)據(jù)和如何把數(shù)據(jù)放入到子窗口控件中去就可以了。 在程序中對話框和菜單一樣被定義成一種資源,您可以在腳本文件中寫一個對話框模板,其中包含該對話框和子窗口的特性, 然后用資源編輯器編輯。需要注意的是所有的資源必須放在同一個腳本文件中。 雖然可以用文本編輯器去編輯腳本文件,但是象要調(diào)整子窗口控件位置時要涉及到一些坐標(biāo)值時最好還是用一些可視化的編 輯器,這樣方便多了。一般在編譯器的開發(fā)包中都會帶資源編輯器,您可以用它們來產(chǎn)生一個模板然后增刪一些子窗口控件。 有兩種主要的對話框:模式對話框和無模式對話框。無模式對話框允許您把輸入焦點切換到(同一個應(yīng)用程序的)另一個窗口,而該對話框無須關(guān)閉 。比如MS WORD 中的FIND對話框。模式對話框又有兩類:應(yīng)用程序模式對話框和系統(tǒng)對話框。應(yīng)用程序?qū)υ捒虿辉试S您在本 應(yīng)用程序中切換輸入焦點,但是可以切換到其它的應(yīng)用程序中去,而系統(tǒng)對話框則必須您對該對話框做出響應(yīng)否則不能切換到 任何的應(yīng)用程序中去。要創(chuàng)建一個無模式對話框調(diào)用API函數(shù)CreateDialogParam,而創(chuàng)建一個模式對話框則調(diào)用API函數(shù)DialogBoxParam。 其中應(yīng)用程序模式對話框和系統(tǒng)模式對話框之間的差別是style參數(shù)不同,要想創(chuàng)建一個系統(tǒng)模式對話框該參數(shù)必須“或”上 DS_SYSMODAL標(biāo)志位。在對話框中若要和子窗口控件通訊則調(diào)用函數(shù)SendDlgItemMesage。該函數(shù)的語法如下:
SendDlgItemMessage proto hwndDlg:DWORD,\
idControl:DWORD,\
uMsg:DWORD,\
wParam:DWORD,\
lParam:DWORD
該PAI函數(shù)對于用在向子窗口控件發(fā)送方面是非常有用的。譬如:如果您想得到編輯控件中的字符串可以這么做:
call SendDlgItemMessage, hDlg, ID_EDITBOX, WM_GETTEXT, 256, ADDR text_buffer
具體要發(fā)送那些消息應(yīng)當(dāng)查詢有關(guān)的WIN32 API 參考手冊。 WINDOWS 還 提供幾個快速存取控件數(shù)據(jù)的函數(shù)。譬如:GetDlgItemText、CheckDlgButton等。這樣一來,您就可以不用去查詢每個消息的wParam和lParam參數(shù)獲得相關(guān)信息了。您應(yīng)盡可能地使用這些API 函數(shù),這樣使得您的代碼將來比較容易維護。對話框的管理函數(shù)會把一些消息發(fā)送給一個特定的回調(diào)函數(shù):對話框過程處理函數(shù),該函數(shù)的格式為:
DlgProc proto hDlg:DWORD ,\
iMsg:DWORD ,\
wParam:DWORD ,\
lParam:DWORD
該函數(shù)的格式非常類似于窗口的過程函數(shù),除了返回值是TURE和FALSE,而不是HRESULT,存在于WINDOWS內(nèi)部的對話框管理器才是對話框真正的窗口過程函數(shù)。它會把某些消息傳遞給我們的窗口過程函數(shù)。所以當(dāng)我們的窗口過程函數(shù)處理這些消息時就返回TTRUE,否則就在eax中返回FALSE。這也意味著我們的窗口過程函數(shù)在接受到自己不處理的消息時并不會調(diào)用DefWindowProc函數(shù),因為它本身不是一個真正的窗口過程函數(shù)。對于對話框有兩種用法:一種是把它作為一個主窗口來用,一種是把它作為一種輸入輸出設(shè)備使用。本課中我們將示范第一種用法。“把對話框用作主窗口”有兩種意思: 1。您可以調(diào)用RegisterClassEx函數(shù)把對話框模板注冊為一個窗口類。這樣該對話框的行為就類似于一個普通的窗口了:它通過在注冊窗口時指定的窗口過程來處理所有的消息,通過這種方法來使用對話框的好處是您不需要顯示地創(chuàng)建子窗口控件,WINDOWS本身會幫您創(chuàng)建好,另外還會幫您處理所有的按鍵邏輯,另外您還可以指定您窗口類結(jié)構(gòu)中的光標(biāo)和圖標(biāo); 2。您的應(yīng)用程序創(chuàng)建沒有父窗口的對話框窗口,這種方法中,沒有必要需要一段處理消息循環(huán)的代碼,因為所有的消息被直接送到對話框過程處理函數(shù),這樣您也可以不要注冊一個窗口類。本課中我門將先使用第一種方法然后使用第二中方法。
例子:
--------------------------------------------------------------------------------
dialog.asm
--------------------------------------------------------------------------------
.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 "DLGCLASS",0
MenuName db "MyMenu",0
DlgName db "MyDialog",0
AppName db "Our First Dialog Box",0
TestString db "Wow! I'm in an edit box now",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
buffer db 512 dup(?)
.const
IDC_EDIT equ 3000
IDC_BUTTON equ 3001
IDC_EXIT equ 3002
IDM_GETTEXT equ 32000
IDM_CLEAR equ 32001
IDM_EXIT equ 32002
.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 hDlg: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,DLGWINDOWEXTRA
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 CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL
mov hDlg,eax
invoke ShowWindow, hDlg,SW_SHOWNORMAL
invoke UpdateWindow, hDlg
invoke GetDlgItem,hDlg,IDC_EDIT
invoke SetFocus,eax
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke IsDialogMessage, hDlg, ADDR msg
.IF eax ==FALSE
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDIF
.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_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_GETTEXT
invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSEIF ax==IDM_CLEAR
invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
mov edx,wParam
shr edx,16
.IF dx==BN_CLICKED
.IF ax==IDC_BUTTON
invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
.ELSEIF ax==IDC_EXIT
invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
--------------------------------------------------------------------------------
Dialog.rc
--------------------------------------------------------------------------------
#include "resource.h"
#define IDC_EDIT 3000
#define IDC_BUTTON 3001
#define IDC_EXIT 3002
#define IDM_GETTEXT 32000
#define IDM_CLEAR 32001
#define IDM_EXIT 32003
MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our First Dialog Box"
CLASS "DLGCLASS"
BEGIN
EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13
PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13, WS_GROUP
END
MyMenu MENU
BEGIN
POPUP "Test Controls"
BEGIN
MENUITEM "Get Text", IDM_GETTEXT
MENUITEM "Clear Text", IDM_CLEAR
MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "E&xit", IDM_EXIT
END
END
分析:
我們先來分析第一個例子:
該例顯示了如何把一個對話框模板注冊成一個窗口類,然后創(chuàng)建一個由該窗口類派生的窗口。由于您沒有必要自己去創(chuàng)建子窗口控件,所以就簡化了許多的工作。
我們先來分析對話框模板。
MyDialog DIALOG 10, 10, 205, 60
先是對話框的名字,然后是關(guān)鍵字“DAILOG”。接下來的四個數(shù)字中,前兩個是對話框的坐標(biāo),后兩個是對話框的寬和高(注意:它們的單位是對話框的單位,而不一定是像素點)。
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -