Win32API学习笔记第七章(二)

来源:互联网 发布:红叶知弦调教 编辑:程序博客网 时间:2024/05/18 12:32

其实对话框不止这些(子窗口控件)
在书上我们可以看见,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上实现,无法显示窗口,目前不知道原因,找到了原因的话会即使更新的)