⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 7. 鼠标.txt

📁 本书介绍了在Microsoft Windows 98、Microsoft Windows NT 4.0和Windows NT 5.0下程序写作的方法
💻 TXT
📖 第 1 页 / 共 5 页
字号:
        
           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                      = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
        
           wndclass.lpszMenuName                        = NULL ;
        
           wndclass.lpszClassName = szAppName ;
        
           if (!RegisterClass (&wndclass))
        
           {
        
            MessageBox (  NULL, TEXT ("Program requires Windows NT!"),
        
                                                                        szAppName, MB_ICONERROR) ;
        
          return 0 ;
        
           }
        
   
        
    wndclass.lpfnWndProc                         = ChildWndProc ;
        
           wndclass.cbWndExtra                  = sizeof (long) ;
        
           wndclass.hIcon                       = NULL ;
        
           wndclass.lpszClassName               = szChildClass ;
        

         RegisterClass (&wndclass) ;
        
           hwnd = CreateWindow (szAppName, TEXT ("Checker3 Mouse Hit-Test Demo"),
        
                        WS_OVERLAPPEDWINDOW,
        
                       CW_USEDEFAULT, CW_USEDEFAULT,
        
                        CW_USEDEFAULT, CW_USEDEFAULT,
        
                        NULL, NULL, hInstance, NULL) ;
        
   
        
           ShowWindow (hwnd, iCmdShow) ;
        
           UpdateWindow (hwnd) ;
        
   
        
           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 HWND   hwndChild[DIVISIONS][DIVISIONS] ;
        
           int                           cxBlock, cyBlock, x, y ;
        
   
        
           switch (message)
        
    {
        
           case   WM_CREATE :
        
                 for (x = 0 ; x < DIVISIONS ; x++)
        
                          for (y = 0 ; y < DIVISIONS ; y++)
        
                   hwndChild[x][y] = CreateWindow (szChildClass, NULL,
        
                   WS_CHILDWINDOW | WS_VISIBLE,
        
                   0, 0, 0, 0,
        
                  hwnd, (HMENU) (y << 8 | x),
        
                   (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
        
                                                                                   NULL) ;
        
                  return 0 ;
        
             
        
           case   WM_SIZE :
        
                  cxBlock = LOWORD (lParam) / DIVISIONS ;
        
                  cyBlock = HIWORD (lParam) / DIVISIONS ;
        
                  for (x = 0 ; x < DIVISIONS ; x++)
        
                                        for (y = 0 ; y < DIVISIONS ; y++)
        
                                                         MoveWindow (  hwndChild[x][y],
        
                                                 x * cxBlock, y * cyBlock,
        
                                                   cxBlock, cyBlock, TRUE) ;
        
                  return 0 ;
        

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

LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message,
        
               WPARAM wParam, LPARAM lParam)
        
{
        
           HDC                                          hdc ;
        
           PAINTSTRUCT                          ps ;
        
           RECT                                         rect ;
        
   
        
           switch (message)
        
          {
        
           case   WM_CREATE :
        
                  SetWindowLong (hwnd, 0, 0) ;       // on/off flag
        
                  return 0 ;
        
        
        
           case   WM_LBUTTONDOWN :
        
                  SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
        
                  InvalidateRect (hwnd, NULL, FALSE) ;
        
                return 0 ;
        
       
        
           case   WM_PAINT :
        
                  hdc = BeginPaint (hwnd, &ps) ;
        
        
        
                  GetClientRect (hwnd, &rect) ;
        
                  Rectangle (hdc, 0, 0, rect.right, rect.bottom) ;
        
        
        
                  if (GetWindowLong (hwnd, 0))
        
                  {
        
                                        MoveToEx (hdc, 0,          0, NULL) ;
        
                                         LineTo   (hdc, rect.right, rect.bottom) ;
        
                                         MoveToEx (hdc, 0,          rect.bottom, NULL) ;
        
                                         LineTo   (hdc, rect.right, 0) ;
        
                  }
        
        
        
                EndPaint (hwnd, &ps) ;
        
                  return 0 ;
        
           }
        
           return DefWindowProc (hwnd, message, wParam, lParam) ;
        
}
        
CHECKER3有两个窗口消息处理程序WndProc和ChildWndProc。WndProc还是主(或父)窗口的窗口消息处理程序。ChildWndProc是针对25个子窗口的窗口消息处理程序。这两个窗口消息处理程序都必须定义为CALLBACK函数。

因为窗口消息处理程序与特定的窗口类别结构相关联,该窗口类别结构由Windows呼叫RegisterClass函数来注册,CHECKER3需要两个窗口类别。第一个窗口类别用于主窗口,名为「Checker3」。第二个窗口类别名为「Checker3_Child」。当然,您不必选择像这样有意义的名字。

CHECKER3在WinMain函数中注册了这两个窗口类别。注册完常规的窗口类别之后,CHECKER3只是简单地重新使用wndclass结构中的大多数的字段来注册Checker3_Child类别。无论如何,有四个字段根据子窗口类别而设定为不同的值:

pfnWndProc字段设定为ChildWndProc,子窗口类别的窗口消息处理程序。
  
cbWndExtra字段设定为4字节,或者更确切地用sizeof (long)。该字段告诉Windows在其为依据此窗口类别的窗口保留的内部结构中,预留了4字节额外的空间。您能使用此空间来保存每个窗口的可能有所不同的信息。
  
因为像CHECKER3中的子窗口不需要图标,所以hIcon字段设定为NULL 。
  
pszClassName字段设定为「Checker3_Child」,是类别的名称。
  
通常,在WinMain中,CreateWindow呼叫建立依据Checker3类别的主窗口。然而,当WndProc收到WM_CREATE消息后,它呼叫CreateWindow 25次以建立25个Checker3_Child类别的子窗口。表7-3是在WinMain中CreateWindow呼叫的参数,与在建立25个子窗口的WndProc中CreateWindow呼叫的参数间的比较。

表7-3
 


参数
 主窗口
 子窗口
 
窗口类别
 「Checker3」
 「Checker3_Child」
 
窗口标题
 「Checker3...」
 NULL
 
窗口样式
 WS_OVERLAPPEDWINDOW
 WS_CHILDWINDOW | WS_VISIBLE
 
水平位置
 CW_USEDEFAULT
 0
 
垂直位置
 CW_USEDEFAULT
 0
 
宽度
 CW_USEDEFAULT
 0
 
高度
 CW_USEDEFAULT
 0
 
父窗口句柄
 NULL
 hwnd
 
菜单句柄/子ID
 NULL
 (HMENU) (y << 8 | x)
 
执行实体句柄
 hInstance
 (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE)
 
额外参数
 NULL
 NULL
 

一般情况下,子窗口要求有关位置和大小的参数,但是在CHECKER3中的子窗口由WndProc确定位置和大小。对于主窗口,因为它本身就是父窗口,所以它的父窗口句柄是NULL。当使用CreateWindow呼叫来建立一个子窗口时,就需要父窗口句柄了。

主窗口没有菜单,因此参数是NULL。对于子窗口,相同位置的参数称为子ID(或子窗口ID)。这是唯一代表子窗口的数字。像我们在第十一章将看到的一样,在处理对话框的子窗口控件时,子ID显得更为重要。对于CHECKER3来说,我只是简单地将子ID设定为一个数值,该数值是每个子窗口在5×5的主窗口中的x和y位置的组合。

CreateWindow函数需要一个执行实体句柄。在WinMain中,执行实体句柄可以很容易地取得,因为它是WinMain的一个参数。在建立子窗口时, CHECKER3必须用GetWindowLong来从Windows为窗口保留的结构中取得hInstance值(相对于GetWindowLong,我也能将hInstance的值保存到整体变量,并直接使用它)。

每一个子窗口都在hwndChild数组中保存了不同的窗口句柄。当WndProc接收到一个WM_SIZE消息后,它将为这25个子窗口呼叫MoveWindow。MoveWindow的参数表示子窗口左上角相对于父窗口显示区域的坐标、子窗口的宽度和高度以及子窗口是否需要重画。

现在让我们看一下ChildWndProc。此窗口消息处理程序为所有这25个子窗口处理消息。ChildWndProc的hwnd参数是子窗口接收消息的句柄。当ChildWndProc处理WM_CREATE消息时(因为有25个子窗口,所以要发生25次),它用SetWindowWord在窗口结构保留的额外区域中储存一个0值(通过在定义窗口类别时使用的cbWndExtra来保留的空间)。ChildWndProc用此值来恢复目前矩形的状态(有X或没有X)。在子窗口中单击时,WM_LBUTTONDOWN处理例程简单地修改这个整数值(从0到1,或从1到0),并使整个子窗口无效。此区域是被单击的矩形。WM_PAINT的处理很简单,因为它所绘制的矩形与显示区域一样大。

因为CHECKER3的C原始码文件和.EXE文件比CHECKER1的大(更不用说程序的说明了),我不会试着告诉你说CHECKER3比CHECKER1更简单。但请注意,我们没有做任何的鼠标命中测试!我们所要的,就是知道CHECKER3中是否有个子窗口得到了命中窗口的WM_LBUTTONDOWN消息。

子窗口和键盘


为CHECKER3添加键盘接口就像CHECKER系列构想中的最后一步。但在这样做的时候,可能有更适当的做法。在CHECKER2中,鼠标光标的位置决定按下Spacebar键时哪个区域将获得标记符号。当我们处理子窗口时,我们能从对话框功能中获得提示。在对话框中,带有闪烁的插入符号或点划的矩形的子窗口表示它有输入焦点(当然也可以用键盘进行定位)。

我们不需要把Windows内部已有的对话框处理方式重

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -