?? 010.txt
字號:
第十課 以對話框為主要界面的應用程序
--------------------------------------------------------------------------------
現在我們開始學習一些有關GUI編程的有趣的部分, 即:以對話框為主要界面的應用程序。我們將分兩課來講述這一過程
理論:
如果您仔細關注過前一個程序就會發現:您無法按TAB鍵從一個子窗口控件跳到另一個子窗口控件,要想轉移的話只有 用鼠標一下一下地去點擊。對用戶來說這是不友好的。另一件事是如果您象前一課中那樣把主窗口的背景色從白色改成 灰色,為了子窗口控件無縫地作相應地改變,您必須細分類所有子窗口。 造成上述諸多不便的原因是子窗口控件本來是為對話框而設計的,象子窗口控件的背景色是灰色的,而對話框的背景色也是 灰色的,這樣它們本來就相互協調了,而無須程序員加入其他的處理。 在我們深入討論對話框前我們必須知道何謂對話框。一個對話框其實是有很多的子窗口控件的一個窗口,WINDOWS在對話框 內部有一個管理程序,由其來處理象按下TAB鍵則輸入焦點從一個子窗口空間條到另一個子窗口控件、按下ENTER鍵等于在當 前具有輸入焦點的子窗口控件上點擊了鼠標 等等這些雜事,這樣程序員就可以集中精力于他們的邏輯事務了。對話框主要用 作輸入輸出接口,人們無須知道它們內部的工作原理,而只要知道如何和他們進行交互就可以了。這也是面向對象設計中的 所謂信息隱藏。只要這個黑盒子中的實現足夠完美,我們就可以放心地使用,當然我們必須強調的是“黑盒子”必須完美。 WIN32 API 內部 的實現即是一個“黑盒子”。 噢,好象我們的討論有些走題,現在讓我們回到正題來,對話框的設計是為了減少程序員的工作量的,一般您如果在窗口中 自己放一個子窗口控件您就必須自己處理其中的按鍵邏輯和細分類它的窗口過程。如果您把它放到對話框中,則這些雜事 對話框會自己處理,您只要知道如何獲得用戶輸入的數據和如何把數據放入到子窗口控件中去就可以了。 在程序中對話框和菜單一樣被定義成一種資源,您可以在腳本文件中寫一個對話框模板,其中包含該對話框和子窗口的特性, 然后用資源編輯器編輯。需要注意的是所有的資源必須放在同一個腳本文件中。 雖然可以用文本編輯器去編輯腳本文件,但是象要調整子窗口控件位置時要涉及到一些坐標值時最好還是用一些可視化的編 輯器,這樣方便多了。一般在編譯器的開發包中都會帶資源編輯器,您可以用它們來產生一個模板然后增刪一些子窗口控件。 有兩種主要的對話框:模式對話框和無模式對話框。無模式對話框允許您把輸入焦點切換到(同一個應用程序的)另一個窗口,而該對話框無須關閉 。比如MS WORD 中的FIND對話框。模式對話框又有兩類:應用程序模式對話框和系統對話框。應用程序對話框不允許您在本 應用程序中切換輸入焦點,但是可以切換到其它的應用程序中去,而系統對話框則必須您對該對話框做出響應否則不能切換到 任何的應用程序中去。要創建一個無模式對話框調用API函數CreateDialogParam,而創建一個模式對話框則調用API函數DialogBoxParam。 其中應用程序模式對話框和系統模式對話框之間的差別是style參數不同,要想創建一個系統模式對話框該參數必須“或”上 DS_SYSMODAL標志位。在對話框中若要和子窗口控件通訊則調用函數SendDlgItemMesage。該函數的語法如下:
SendDlgItemMessage proto hwndDlg:DWORD,\
idControl:DWORD,\
uMsg:DWORD,\
wParam:DWORD,\
lParam:DWORD
該PAI函數對于用在向子窗口控件發送方面是非常有用的。譬如:如果您想得到編輯控件中的字符串可以這么做:
call SendDlgItemMessage, hDlg, ID_EDITBOX, WM_GETTEXT, 256, ADDR text_buffer
具體要發送那些消息應當查詢有關的WIN32 API 參考手冊。 WINDOWS 還 提供幾個快速存取控件數據的函數。譬如:GetDlgItemText、CheckDlgButton等。這樣一來,您就可以不用去查詢每個消息的wParam和lParam參數獲得相關信息了。您應盡可能地使用這些API 函數,這樣使得您的代碼將來比較容易維護。對話框的管理函數會把一些消息發送給一個特定的回調函數:對話框過程處理函數,該函數的格式為:
DlgProc proto hDlg:DWORD ,\
iMsg:DWORD ,\
wParam:DWORD ,\
lParam:DWORD
該函數的格式非常類似于窗口的過程函數,除了返回值是TURE和FALSE,而不是HRESULT,存在于WINDOWS內部的對話框管理器才是對話框真正的窗口過程函數。它會把某些消息傳遞給我們的窗口過程函數。所以當我們的窗口過程函數處理這些消息時就返回TTRUE,否則就在eax中返回FALSE。這也意味著我們的窗口過程函數在接受到自己不處理的消息時并不會調用DefWindowProc函數,因為它本身不是一個真正的窗口過程函數。對于對話框有兩種用法:一種是把它作為一個主窗口來用,一種是把它作為一種輸入輸出設備使用。本課中我們將示范第一種用法。“把對話框用作主窗口”有兩種意思: 1。您可以調用RegisterClassEx函數把對話框模板注冊為一個窗口類。這樣該對話框的行為就類似于一個普通的窗口了:它通過在注冊窗口時指定的窗口過程來處理所有的消息,通過這種方法來使用對話框的好處是您不需要顯示地創建子窗口控件,WINDOWS本身會幫您創建好,另外還會幫您處理所有的按鍵邏輯,另外您還可以指定您窗口類結構中的光標和圖標; 2。您的應用程序創建沒有父窗口的對話框窗口,這種方法中,沒有必要需要一段處理消息循環的代碼,因為所有的消息被直接送到對話框過程處理函數,這樣您也可以不要注冊一個窗口類。本課中我門將先使用第一種方法然后使用第二中方法。
例子:
--------------------------------------------------------------------------------
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
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
分析:
我們先來分析第一個例子:
該例顯示了如何把一個對話框模板注冊成一個窗口類,然后創建一個由該窗口類派生的窗口。由于您沒有必要自己去創建子窗口控件,所以就簡化了許多的工作。
我們先來分析對話框模板。
MyDialog DIALOG 10, 10, 205, 60
先是對話框的名字,然后是關鍵字“DAILOG”。接下來的四個數字中,前兩個是對話框的坐標,后兩個是對話框的寬和高(注意:它們的單位是對話框的單位,而不一定是像素點)。
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -