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 = ;
  25. wndclass.cbWndExtra = ;
  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 ;
  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, , ))
  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 ;
  74.  
  75. case WM_SETFOCUS:
  76. ShowCursor(TRUE);
  77. return ;
  78.  
  79. case WM_KILLFOCUS:
  80. ShowCursor(FALSE);
  81. return ;
  82.  
  83. case WM_KEYDOWN:
  84. GetCursorPos(&point);
  85. ScreenToClient(hwnd, &point);
  86.  
  87. x = max(, min(DIVISIONS - , point.x / cxBlock));
  88. y = max(, min(DIVISIONS - , 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 = ;
  110. break;
  111.  
  112. case VK_END:
  113. x = y = DIVISIONS - ;
  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 / ;
  126. point.y = y * cyBlock + cyBlock / ;
  127.  
  128. ClientToScreen(hwnd, &point);
  129. SetCursorPos(point.x, point.y);
  130. return ;
  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] ^= ;
  139.  
  140. rect.left = x * cxBlock;
  141. rect.top = y * cyBlock;
  142. rect.right = (x + ) * cxBlock;
  143. rect.bottom = (y + ) * cyBlock;
  144.  
  145. InvalidateRect(hwnd, &rect, FALSE);
  146. }
  147. else
  148. MessageBeep();
  149. return ;
  150.  
  151. case WM_PAINT:
  152. hdc = BeginPaint(hwnd, &ps);
  153.  
  154. for (x = ; x < DIVISIONS; ++x)
  155. for (y = ; y < DIVISIONS; ++y)
  156. {
  157. Rectangle(hdc, x * cxBlock, y * cyBlock
  158. , (x + ) * cxBlock, (y + ) * cyBlock);
  159.  
  160. if (fState[x][y])
  161. {
  162. MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL);
  163. LineTo(hdc, (x + ) * cxBlock, (y + ) * cyBlock);
  164. MoveToEx(hdc, x * cxBlock, (y + ) * cyBlock, NULL);
  165. LineTo(hdc, (x + ) * cxBlock, y * cyBlock);
  166. }
  167. }
  168.  
  169. EndPaint(hwnd, &ps);
  170. return ;
  171.  
  172. case WM_DESTROY:
  173. PostQuitMessage();
  174. return ;
  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设置指针的位置。

第七章 鼠标(CHECKER2)的更多相关文章

  1. 第七章 鼠标(CHECKER1)

    CHECKER1程序将客户区划分成25个矩形,构成一个5*5的数组.如果在其中一个矩形内单击鼠标,就用X形填充该矩形.再次单击,则X形消失. /*--------------------------- ...

  2. 第七章 鼠标(CHECKER4)

    /*--------------------------------------------- CHECKER4.C -- Mouse Hit-Test Demo Program No.4 (c) C ...

  3. 第七章 鼠标(CHECKER3)

    /*--------------------------------------------- CHECKER3.C -- Mouse Hit-Test Demo Program No.3 (c) C ...

  4. 第七章 鼠标(CONNECT)

    /* CONNECT.C -- Connect-the-Dots Mouse Demo Program (c) Charles Petzold,1998 */ #include <Windows ...

  5. 第七章 探秘Qt的核心机制-信号与槽

    第七章 探秘Qt的核心机制-信号与槽 注:要想使用Qt的核心机制信号与槽,就必须在类的私有数据区声明Q_OBJECT宏,然后会有moc编译器负责读取这个宏进行代码转化,从而使Qt这个特有的机制得到使用 ...

  6. (转)iOS Wow体验 - 第七章 - 操作图例与触屏人机工学

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第七章译文精选,其余章节将陆续放出.上一篇:Wow ...

  7. 【转】第七章、Linux 文件与目录管理

    原文网址:http://vbird.dic.ksu.edu.tw/linux_basic/0220filemanager.php 第七章.Linux 文件与目录管理 最近升级日期:2009/08/26 ...

  8. 【知识强化】第七章 输入/输出系统 7.1 I/O系统基本概念

    那么下面,我们将要进入计算机组成原理的最后一章,也就是我们的第七章,输入输出系统的学习.那么这一部分内容呢,我们之前呢一直在提,但是并没有详细地讲解,那么进入到我们第七章输入输出系统这一部分,我们就要 ...

  9. 精通Web Analytics 2.0 (9) 第七章:失败更快:爆发测试与实验的能量

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第七章:失败更快:爆发测试与实验的能量 欢迎来到实验和测试这个棒极了的世界! 如果Web拥有一个超越所有其他渠道的巨大优势,它就 ...

随机推荐

  1. 与LINQ有关的语言特性

    在说LINQ之前必须先说说几个重要的C#语言特性 一:与LINQ有关的语言特性 1.隐式类型 (1)源起 在隐式类型出现之前, 我们在声明一个变量的时候, 总是要为一个变量指定他的类型 甚至在fore ...

  2. python虚拟环境 | virtualenv 的简单使用 (图文)

    一.创建virtualenv虚拟环境 mkvirtualenv -p 版本号 虚拟名 mkvirtualenv -p python3 env_1 python3:版本号 env_1: 虚拟环境名称 创 ...

  3. SQL 必知必会·笔记<10>联结表

    可伸缩(scale) 能够适应不断增加的工作量而不失败.设计良好的数据库或应用程序 称为可伸缩性好(scale well). 联结(JOIN) 联结(JOIN)是一种机制,用来在一条SELECT 语句 ...

  4. Quartz.NET的简单任务管理类

    昨天使用Quartz.NET做了个定时任务的功能,并实现了多个定时任务的功能 下面这个类实现了如下功能: 1.对定时任务进行管理 2.创建定时任务,需要给定时任务一个job的名称 3.判断给定的job ...

  5. 声明父类new子类

    基本概念 这个实例是子类的,但是因为你声明时是用父类声明的,所以你用正常的办法访问不到子类自己的成员,只能访问到从父类继承来的成员. 在子类中用override重写父类中用virtual申明的虚方法时 ...

  6. APiCloud学习

    端API调用 核心模块在 window.api 对象下,默认提供该模块,不需要单独引用. 扩展模块在相应的模块对象下(例如:文件系统模块在fs对象下),需要require引入(var fs = api ...

  7. CASE函数

    -> 使用类似switch-case与if-else if -> 语法 •case [字段] •    when 表达式 then 显示数据 •    when 表达式 then 显示数据 ...

  8. HibernateTemplate的用法以及作用

    HibernateTemplate作用:从字面上意思我们就知道他是一个模板,然后我们又知道hibernate是一个对象关系映射的框架,所以我们很容易联想到他的功能就是将Hibernate 的持久层访问 ...

  9. 本地计算机上的MySQL服务启动后停止。某些服务在未由其他服务或程序使用时将自动

    重新安装MySQL数据库,由于安装的时候马虎,一路next(事实上,某些地方需要严格的配置,我忘记注意了),导致现在出了很多麻烦. 错误信息: 本地计算机上的MySQL服务启动后停止.某些服务在未由其 ...

  10. 【redis】7、redis用法总结

    Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 一.redis优点 Redis支持数据的持久化,可以将内存中 ...