欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Win32API学习笔记第七章(二)

程序员文章站 2024-03-14 23:40:29
...

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