第十章

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) ;

第十一章

与窗口消息处理程序类似,对话框程序都必须定义为一个CALLBACKcallback)函数。尽管我使用了hDlg作为对话框窗口的句柄,但是您也可以按照您自己的意思使用hwnd。首先,让我们来看一下这个函数与窗口消息处理程序的区别:

· 窗口消息处理程序传回一个LRESULT。对话框传回一个BOOL,它在Windows表头文件中定义为int型态。
 

· 如果窗口消息处理程序不处理某个特定的消息,那么它将呼叫DefWindowProc。如果对话框程序处理一个消息,那么它传回TRUE(非0),如果不处理,则传回FALSE0)。
 

· 对话框程序不需要处理WM_PAINTWM_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);否则,它将传回FALSE0)。只有hDlgModeless0或者消息不是该对话框的消息时,才必须呼叫TranslateMessageDispatchMessage函数。如果您将键盘快捷键用于您的程序窗口,那么消息循环将如下所示:

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) ;

}