Win32API學習筆記第七章(二)

其實對話框不止這些(子窗口控件)
在書上我們可以看見,About3這個程序,實際上是自繪了一個確認圖標。
首先我們自己給這個圖標定義了一個類(說白了,這個圖標實際上就是一個窗口,只是這裏的窗口類被封裝到了一個叫CustomControl的子窗口控制裏面,這個控件會把Class這一欄空出來由用戶自己選,然後實際上在創建了Dialog的時候就會調用CreateWindow來將這個用戶自定的窗口創建出來。
再說下相互切換的Tab鍵相關的兩個API:
GetNextDlgTabItem和GetNextGroupItem這裏就可以得到前一個或後一個Tab鍵停留的組項(然後設置焦點就可以)同時,如果是自己的窗口的話,要加上WS_TABSTOP和WS_GROUP兩個窗口風格纔可以達到這個目的。
然後是非模態對話框:

1:

第一個是主窗口調用一個非模態對話框(這樣子的對話框更像普通的子窗口一點)
此時我們需要自己爲這個對話框寫一個窗口過程,然後是創建窗口時:
CreateDialog(HINSTANCE,PTCHAR,父窗口窗口句柄 ,自己的窗口過程);
在窗口過程內我們就可以自定義各種各樣的消息,並且可以在主窗口和這個對話框之間相互切換,而且很多的一些相關功能都有着對話框的性質,非常的方便
但是我們會發現一個問題:我們的消息循環只有一個,那要怎麼辦?
此時我們就要用到isDialogMessage這個函數來判斷這個消息是否是屬於後一個對話框的:

if(hWnd == 0||!isDialogMessage(hWnd,&msg))
{
    //默認的之前的窗口消息
}

這個函數有兩個作用,第一:如果這個消息時屬於這個對話框的消息,那麼它將返回一個非零值,並且將這個消息發送到相應的窗口過程去,其次:如果這個消息不屬於這個對話框,那麼就返回一個0。
之前加了一個判斷hWnd是否爲0是因爲,如果爲0他將繼續用無效的窗口句柄進行調用這個函數,所以這裏時加以驗證的一個機制,並且,這個hWnd被置爲全局,以便執行:

case WM_CLOSE:
    DestoryWindow(hWnd);
    hWnd = 0;
    return 0;

這裏非模態和模態的區別之一就是這裏並不是調用EndDialog。

2:

我們還可以直接就將這個對話框置爲主窗口,這就會大大簡化了代碼:

WNDCLASS wcex;
    wcex.style = CS_HREDRAW | CS_VREDRAW | WS_VISIBLE;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = DLGWINDOWEXTRA;    // 這裏必須爲DLGWINDOWEXTRA
    wcex.hInstance      = hInstance;
...
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;

//然後是註冊,之後就用
CreateDialog(HINSTANCE,PTCHAR,0,0);//後面兩個爲NULL就可以了

此時說實話這個就是一個窗口的創建(其尺寸,文字尺寸,標題都在資源文件裏面聲明瞭)兩者時等價關係。
來看一個書上非常典型的例子:

/*----------------------------------------
   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.style         = CS_HREDRAW | CS_VREDRAW;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = DLGWINDOWEXTRA ;    // Note!
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateDialog (hInstance, szAppName, 0, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

void ShowNumber (HWND hwnd, UINT iNumber)
{
     TCHAR szBuffer[20] ;

     wsprintf (szBuffer, TEXT ("%X"), iNumber) ;
     SetDlgItemText (hwnd, VK_ESCAPE, szBuffer) ;
}

DWORD CalcIt (UINT iFirstNum, int iOperation, UINT iNum)
{
     switch (iOperation)
     {
     case '=': return iNum ;
     case '+': return iFirstNum +  iNum ;
     case '-': return iFirstNum -  iNum ;
     case '*': return iFirstNum *  iNum ;
     case '&': return iFirstNum &  iNum ;
     case '|': return iFirstNum |  iNum ;
     case '^': return iFirstNum ^  iNum ;
     case '<': return iFirstNum << iNum ;
     case '>': return iFirstNum >> iNum ;
     case '/': return iNum ? iFirstNum / iNum: MAXDWORD ;
     case '%': return iNum ? iFirstNum % iNum: MAXDWORD ;
     default : return 0 ;
     }
}

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 ;
                                        // fall through
     case WM_CHAR:
          if ((wParam = (WPARAM) CharUpper ((TCHAR *) wParam)) == VK_RETURN)
               wParam = '=' ;

          if (hButton = GetDlgItem (hwnd, wParam))
          {
               SendMessage (hButton, BM_SETSTATE, 1, 0) ;
               Sleep (100) ;
               SendMessage (hButton, BM_SETSTATE, 0, 0) ;
          }
          else
          {
               MessageBeep (0) ;
               break ;
          }
                                        // fall through
     case WM_COMMAND:
          SetFocus (hwnd) ;

          if (LOWORD (wParam) == VK_BACK)         // backspace
               ShowNumber (hwnd, iNumber /= 16) ;

          else if (LOWORD (wParam) == VK_ESCAPE)  // escape
               ShowNumber (hwnd, iNumber = 0) ;

          else if (isxdigit (LOWORD (wParam)))    // hex digit
          {
               if (bNewNumber)
               {
                    iFirstNum = iNumber ;
                    iNumber = 0 ;
               }
               bNewNumber = FALSE ;

               if (iNumber <= MAXDWORD >> 4)
                    ShowNumber (hwnd, iNumber = 16 * iNumber + wParam -
                    (isdigit (wParam) ? '0': 'A' - 10)) ;
               else
                    MessageBeep (0) ;
          }
          else                                    // operation
          {
               if (!bNewNumber)
                    ShowNumber (hwnd, iNumber =
                         CalcIt (iFirstNum, iOperation, iNumber)) ;
               bNewNumber = TRUE ;
               iOperation = LOWORD (wParam) ;
          }
          return 0 ;

     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

非常巧妙的是:
這裏將所有的非Char類鍵盤消息全部丟給了默認的窗口過程處理,那麼只需要在控件支持的情況下,我們就可以做到Tab切換等一系列操作,並且藉助於每個消息之間的關係,將撤回鍵(VK_BACK)一直下調到COMMAND,回車鍵轉化等等。。。。
(這個程序我自己在VS2017上實現,無法顯示窗口,目前不知道原因,找到了原因的話會即使更新的)

發佈了46 篇原創文章 · 獲贊 24 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章