第十章
hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ;
取得圖示的句柄。使用敘述
cxIcon = GetSystemMetrics (SM_CXICON) ;
cyIcon = GetSystemMetrics (SM_CYICON) ;
取得圖示的大小。然後,程序通過多次呼叫
DrawIcon (hdc, x, y, hIcon) ;
#define MAKEINTRESOURCE(i) (LPTSTR) ((DWORD) ((WORD) (i)))
hMenu = LoadMenu (hInstance, TEXT ("MyMenu")) ;
如果使用了數值,那麼LoadMenu呼叫採用如下的形式:
hMenu = LoadMenu (hInstance, MAKEINTRESOURCE (ID_MENU)) ;
然後,您可以將這個菜單句柄作爲CreateWindow的第九個參數:
hwnd=CreateWindow(TEXT("MyClass"),TEXT("WindowCaption"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, hMenu, hInstance, NULL) ;
您也可以在窗口類別中指定NULL菜單,並且在CreateWindow呼叫中也指定NULL菜單,然後在窗口被建立後再給窗口指定一個菜單:
SetMenu (hwnd, hMenu) ;
第十一章
與窗口消息處理程序類似,對話框程序都必須定義爲一個CALLBACK(callback)函數。儘管我使用了hDlg作爲對話框窗口的句柄,但是您也可以按照您自己的意思使用hwnd。首先,讓我們來看一下這個函數與窗口消息處理程序的區別:
· 窗口消息處理程序傳回一個LRESULT。對話框傳回一個BOOL,它在Windows表頭文件中定義爲int型態。
· 如果窗口消息處理程序不處理某個特定的消息,那麼它將呼叫DefWindowProc。如果對話框程序處理一個消息,那麼它傳回TRUE(非0),如果不處理,則傳回FALSE(0)。
· 對話框程序不需要處理WM_PAINT或WM_DESTROY消息。對話框程序不接收WM_CREAT消息,而是在特殊的WM_INITDIALOG消息處理期間,對話框程序執行初始化操作。
WM_INITDIALOG消息是對話框接收到的第一個消息,這個消息只發送給對話框程序。如果對話框程序傳回TRUE,那麼Windows將輸入焦點設定給對話框中第一個具有WS_TABSTOP樣式(我們將在ABOUT2的討論中加以解釋)的子窗口控件。在這個對話框中,第一個具有WS_TABSTOP樣式的子窗口控件是按鍵。另外,對話框程序也可以在處理WM_INITDIALOG時使用SetFocus來將輸入焦點設定爲對話框中的某個子窗口控件,然後傳回FALSE。
此外,對話框程序只處理WM_COMMAND消息。這是當按鍵被鼠標點中,或者在按鈕具有輸入焦點的情況下按下空格鍵時,按鍵控件發送給其父窗口的消息。這個控件的ID(我們在對話框模板中將其設定爲IDOK)在wParam的低字組中。對於這個消息,對話框過程調用EndDialog,它告訴Windows清除對話框。對於所有其它消息,對話框程序傳回FALSE,並告訴Windows內部的對話框窗口消息處理程序:我們的對話框程序不處理這些消息。
模態對話框的消息不通過您程序的消息隊列,所以不必擔心對話框中鍵盤快捷鍵的影響。
即使在顯示對話框時,WndProc也可以繼續接收消息。實際上,您可以從對話框程序內部給WndProc發送消息。ABOUT1的主窗口是彈出式對話框窗口的父窗口,所以AboutDlgProc中的SendMessage呼叫可以使用如下敘述來開始:
SendMessage (GetParent (hDlg), . . . ) ;
也許您希望受益於Windows對話框管理器,但不希望(或者能夠)在資源描述中定義對話框模板,也可能您希望程序在執行時可以動態地建立對話框。這時可以完成這種功能的函數是DialogBoxIndirect,此函數用數據結構來定義模板。
非模態對話框
您已經看到,模態對話框是用DialogBox來建立的。只有在清除對話框之後,函數纔會傳回值。在對話框程序內使用EndDialog呼叫來終止對話框,DialogBox傳回的是該呼叫的第二個參數的值。非模態對話框是使用CreateDialog來建立的,該函數所使用的參數與DialogBox相同。
hDlgModeless = CreateDialog ( hInstance, szTemplate,hwndParent, DialogProc) ;
區別是CreateDialog函數立即傳回對話框的窗口句柄,並通常將這個窗口句柄存放到整體變量中。
使用非模態對話框與使用模態對話框相似,但是也有一些重要的區別:
首先,非模態對話框通常包含一個標題列和一個系統菜單按鈕。當您在Developer Studio中建立對話框時,這些是內定選項。用於非模態對話框的對話框模板中的STYLE敘述形如:
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
如果省略了WS_VISIBLE,那麼您必須在CreateDialog呼叫之後呼叫ShowWindow:
與模態對話框和消息框的消息不同,非模態對話框的消息要經過程序式的消息隊列。要將這些消息傳送給對話框窗口消息處理程序,則必須改變消息隊列。方法如下:當您使用CreateDialog建立非模態對話框時,應該將從呼叫中傳回的對話框句柄儲存在一個整體變量(如hDlgModeless)中,並將消息循環改變爲:
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
如果消息是發送給非模態對話框的,那麼IsDialogMessage將它發送給對話框中窗口消息處理程序,並傳回TRUE(非0);否則,它將傳回FALSE(0)。只有hDlgModeless爲0或者消息不是該對話框的消息時,才必須呼叫TranslateMessage和DispatchMessage函數。如果您將鍵盤快捷鍵用於您的程序窗口,那麼消息循環將如下所示:
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
{
if (!TranslateAccelerator (hwnd, hAccel, &msg))
{
TranslateMessage(&msg); DispatchMessage (&msg) ;
}
}
}
一個非模態對話框的例子
/*------------------------------------------------
COLORS2.C -- Version using Modeless Dialog Box
(c) Charles Petzold, 1998
------------------------------------------------*/
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK ColorScrDlg (HWND, UINT, WPARAM, LPARAM) ;
HWND hDlgModeless ;
HINSTANCE hinst;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Colors2") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = CreateSolidBrush (0L) ;
wndclass.lpszMenuName = (LPCSTR)IDR_MENU1;
// wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName ;
hinst=hInstance;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Color Scroll"),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
hDlgModeless = CreateDialog (hInstance, dialog1,
hwnd, ColorScrDlg) ;
ShowWindow (hDlgModeless, SW_HIDE) ;
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == ID_MENUITEM40001)
{
ShowWindow(hDlgModeless,SW_SHOWNORMAL);
}
return 0;
case WM_DESTROY :
DeleteObject ((HGDIOBJ) SetClassLong (hwnd, GCL_HBRBACKGROUND,
(LONG) GetStockObject (WHITE_BRUSH))) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
BOOL CALLBACK ColorScrDlg (HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static int iColor[3] ;
HWND hwndParent, hCtrl ;
int iCtrlID, iIndex ;
switch (message)
{
case WM_INITDIALOG :
for (iCtrlID = 10 ; iCtrlID < 13 ; iCtrlID++)
{
hCtrl = GetDlgItem (hDlg, iCtrlID) ;
SetScrollRange (hCtrl, SB_CTL, 0, 255, FALSE) ;
SetScrollPos (hCtrl, SB_CTL, 0, FALSE) ;
}
return TRUE ;
case WM_VSCROLL :
hCtrl = (HWND) lParam ;
iCtrlID = GetWindowLong (hCtrl, GWL_ID) ;
iIndex = iCtrlID - 10 ;
hwndParent = GetParent (hDlg) ;
switch (LOWORD (wParam))
{
case SB_PAGEDOWN :
iColor[iIndex] += 15 ; // fall through
case SB_LINEDOWN :
iColor[iIndex] = min (255, iColor[iIndex] + 1) ;
break ;
case SB_PAGEUP :
iColor[iIndex] -= 15 ; // fall through
case SB_LINEUP :
iColor[iIndex] = max (0, iColor[iIndex] - 1) ;
break ;
case SB_TOP :
iColor[iIndex] = 0 ;
break ;
case SB_BOTTOM :
iColor[iIndex] = 255 ;
break ;
case SB_THUMBPOSITION :
case SB_THUMBTRACK :
iColor[iIndex] = HIWORD (wParam) ;
break ;
default :
return FALSE ;
}
SetScrollPos (hCtrl, SB_CTL, iColor[iIndex], TRUE) ;
SetDlgItemInt (hDlg, iCtrlID + 3, iColor[iIndex], FALSE) ;
DeleteObject ((HGDIOBJ) SetClassLong (hwndParent, GCL_HBRBACKGROUND,
(LONG) CreateSolidBrush (
RGB (iColor[0], iColor[1], iColor[2])))) ;
InvalidateRect (hwndParent, NULL, TRUE) ;
return TRUE ;
}
return FALSE ;
}
以對話框爲主體的程序,注意這點
wndclass.cbWndExtra = DLGWINDOWEXTRA ; // Note!
分配給窗口實例的額外字節數,初始化爲0,如果程序用WNDCLASS註冊由資源文件裏的CLASS指令創建的對話框時,它的值必須設置爲DLGWINDOWEXTRA.
/*----------------------------------------
HEXCALC.C -- Hexadecimal Calculator
(c) Charles Petzold, 1998
----------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HexCalc") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.cbWndExtra = DLGWINDOWEXTRA ; // Note!
if (!RegisterClass (&wndclass))
{
}
hwnd = CreateDialog (hInstance, szAppName, 0, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bNewNumber = TRUE ;
static int iOperation = '=' ;
static UINT iNumber, iFirstNum ;
HWND hButton ;
switch (message)
{
case WM_KEYDOWN: // left arrow --> backspace
if (wParam != VK_LEFT)
break ;
wParam = VK_BACK ;
case WM_COMMAND:
SetFocus (hwnd) ;
if (LOWORD (wParam) == VK_BACK) // backspace
ShowNumber (hwnd, iNumber /= 16) ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}