zoukankan      html  css  js  c++  java
  • 第七章 鼠标(CHECKER2)

    CHECKER2程序包含一个键盘接口,内容与CHECKER1完全相同。利用←、→、↑、↓四个方向键可以在25个矩形之间移动鼠标指针。Home键把鼠标指针移动到左上角的矩形;End键使鼠标指针落到右下角的矩形。空格键和回车键都可以切换X形标记。

      1 /*---------------------------------------------
      2 CHECKER2.C -- Mouse Hit-Test Demo Program No.2
      3               (c) Charles Petzold, 1998
      4 ---------------------------------------------*/
      5 
      6 #include <Windows.h>
      7 
      8 #define DIVISIONS 5
      9 
     10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
     11 
     12 int WINAPI WinMain( __in HINSTANCE hInstance
     13                     , __in_opt HINSTANCE hPrevInstance
     14                     , __in LPSTR lpCmdLine
     15                     , __in int nShowCmd )
     16 {
     17     static TCHAR szAppName[] = TEXT("Checker2");
     18     HWND hwnd;
     19     MSG msg;
     20     WNDCLASS wndclass;
     21 
     22     wndclass.style = CS_HREDRAW | CS_VREDRAW;
     23     wndclass.lpfnWndProc = WndProc;
     24     wndclass.cbClsExtra = 0;
     25     wndclass.cbWndExtra = 0;
     26     wndclass.hInstance = hInstance;
     27     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     28     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
     29     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
     30     wndclass.lpszMenuName = NULL;
     31     wndclass.lpszClassName = szAppName;
     32 
     33     if (!RegisterClass(&wndclass))
     34     {
     35         MessageBox(NULL, TEXT("Program requires Windows NT!")
     36             , szAppName, MB_ICONERROR);
     37         return 0;
     38     }
     39 
     40     hwnd = CreateWindow(szAppName, TEXT("Checker2 Mouse Hit-Test Demo")
     41         , WS_OVERLAPPEDWINDOW
     42         , CW_USEDEFAULT, CW_USEDEFAULT
     43         , CW_USEDEFAULT, CW_USEDEFAULT
     44         , NULL, NULL, hInstance, NULL);
     45 
     46     ShowWindow(hwnd, nShowCmd);
     47     UpdateWindow(hwnd);
     48 
     49     while (GetMessage(&msg, NULL, 0, 0))
     50     {
     51         TranslateMessage(&msg);
     52         DispatchMessage(&msg);
     53     }
     54 
     55     return msg.wParam;
     56 }
     57 
     58 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     59 {
     60     static BOOL fState[DIVISIONS][DIVISIONS];
     61     static int cxBlock, cyBlock;
     62     HDC hdc;
     63     int x, y;
     64     PAINTSTRUCT ps;
     65     POINT point;
     66     RECT rect;
     67 
     68     switch (message)
     69     {
     70     case WM_SIZE:
     71         cxBlock = LOWORD(lParam) / DIVISIONS;
     72         cyBlock = HIWORD(lParam) / DIVISIONS;
     73         return 0;
     74 
     75     case WM_SETFOCUS:
     76         ShowCursor(TRUE);
     77         return 0;
     78 
     79     case WM_KILLFOCUS:
     80         ShowCursor(FALSE);
     81         return 0;
     82 
     83     case WM_KEYDOWN:
     84         GetCursorPos(&point);
     85         ScreenToClient(hwnd, &point);
     86 
     87         x = max(0, min(DIVISIONS - 1, point.x / cxBlock));
     88         y = max(0, min(DIVISIONS - 1, point.y / cyBlock));
     89 
     90         switch (wParam)
     91         {
     92         case VK_UP:
     93             --y;
     94             break;
     95 
     96         case VK_DOWN:
     97             ++y;
     98             break;
     99 
    100         case VK_LEFT:
    101             --x;
    102             break;
    103 
    104         case VK_RIGHT:
    105             ++x;
    106             break;
    107 
    108         case VK_HOME:
    109             x = y = 0;
    110             break;
    111 
    112         case VK_END:
    113             x = y = DIVISIONS - 1;
    114             break;
    115 
    116         case VK_RETURN:
    117         case VK_SPACE:
    118             SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(x * cxBlock, y * cyBlock));
    119             break;
    120         }
    121 
    122         x = (x + DIVISIONS) % DIVISIONS;
    123         y = (y + DIVISIONS) % DIVISIONS;
    124 
    125         point.x = x * cxBlock + cxBlock / 2;
    126         point.y = y * cyBlock + cyBlock / 2;
    127 
    128         ClientToScreen(hwnd, &point);
    129         SetCursorPos(point.x, point.y);
    130         return 0;
    131 
    132     case WM_LBUTTONDOWN:
    133         x = LOWORD(lParam) / cxBlock;
    134         y = HIWORD(lParam) / cyBlock;
    135 
    136         if (x < DIVISIONS && y < DIVISIONS)
    137         {
    138             fState[x][y] ^= 1;
    139 
    140             rect.left = x * cxBlock;
    141             rect.top = y * cyBlock;
    142             rect.right = (x + 1) * cxBlock;
    143             rect.bottom = (y + 1) * cyBlock;
    144 
    145             InvalidateRect(hwnd, &rect, FALSE);
    146         }
    147         else
    148             MessageBeep(0);
    149         return 0;
    150 
    151     case WM_PAINT:
    152         hdc = BeginPaint(hwnd, &ps);
    153 
    154         for (x = 0; x < DIVISIONS; ++x)
    155             for (y = 0; y < DIVISIONS; ++y)
    156             {
    157                 Rectangle(hdc, x * cxBlock, y * cyBlock
    158                     , (x + 1) * cxBlock, (y + 1) * cyBlock);
    159                 
    160                 if (fState[x][y])
    161                 {
    162                     MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL);
    163                     LineTo(hdc, (x + 1) * cxBlock, (y + 1) * cyBlock);
    164                     MoveToEx(hdc, x * cxBlock, (y + 1) * cyBlock, NULL);
    165                     LineTo(hdc, (x + 1) * cxBlock, y * cyBlock);
    166                 }
    167             }
    168 
    169         EndPaint(hwnd, &ps);
    170         return 0;
    171 
    172     case WM_DESTROY:
    173         PostQuitMessage(0);
    174         return 0;
    175     }
    176 
    177     return DefWindowProc(hwnd, message, wParam, lParam);
    178 }
    CHECKER2.C

    在CHECKER2程序中,处理WM_KEYDOWN时利用GetCursorPos判断指针的位置,并利用ScreenToClient将屏幕坐标转换成客户区坐标,然后将坐标值除以矩形块的宽和高,得到x和y。这些x和y的值表示了矩形在5*5数组中的位置。当按下某个键时,鼠标指针可能在客户区也可能不在客户区内,因此x和y必须包含在min和max的宏处理中,保证它们的范围处于0和4之间。

    对于方向键,CHECKER2程序相应的增加或减少x和y的值。若按下回车键或空格键,CHECKER2程序调用SendMessage给自己发送一个WM_LBUTTONDOWN消息。最后,WM_KEYDOWN处理逻辑计算得到指向矩形中心的客户区坐标,并调用ClientToScreen将其转换成屏幕坐标,最后调用SetCursorPos设置指针的位置。

  • 相关阅读:
    LeetCode 326. Power of Three
    LeetCode 324. Wiggle Sort II
    LeetCode 322. Coin Change
    LeetCode 321. Create Maximum Number
    LeetCode 319. Bulb Switcher
    LeetCode 318. Maximum Product of Word Lengths
    LeetCode 310. Minimum Height Trees (DFS)
    个人站点大开发!--起始篇
    LeetCode 313. Super Ugly Number
    LeetCode 309. Best Time to Buy and Sell Stock with Cooldown (DP)
  • 原文地址:https://www.cnblogs.com/web1013/p/9013520.html
Copyright © 2011-2022 走看看