昨天晚上失眠了,于是一直在想实现GDI的一个效果:首先绘制10个相连的矩形,当鼠标移到某个矩形的时候,自动填充那个矩形的背景颜色为灰色,移开的时候恢复原来的白色。当只有一个矩形的时候,当然不是一件难事。但是当有10个矩形的时候,问题就产生了。首先先看一下代码:

#include <windows.h> #include <math.h> #define NUM 10 struct own_rectangle{ int xLeft ; int xRight ; int yTop ; int yBottom ; }rect[NUM]; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("piano demo by mouse"); HWND hwnd; MSG msg; 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.lpszClassName = szAppName; wndclass.lpszMenuName = NULL; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0; } hwnd = CreateWindow (szAppName, TEXT("Piano Demo Using Mouse"), 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 int cxClient, cyClient; static int Flag[NUM] ={0,0,0,0,0,0,0,0,0,0}; HDC hdc; int i = 0; PAINTSTRUCT ps; //ps数组里面存放了RECT,用来重绘客户区的位置 POINT hitPoint; int xCornerEllipse; int yCornerEllipse; int xStart = 200, yStart = 100, xEnd = 100, yEnd = 300; HBRUSH hBrush; HPEN hPen; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_MOUSEMOVE: hitPoint.x = LOWORD(lParam); hitPoint.y = HIWORD(lParam); for (i = 0; i < NUM; i++) //为什么 只有当i=0的时候才有效果呢? { if (hitPoint.x >= rect[i].xLeft && hitPoint.x <= rect[i].xRight && hitPoint.y >= rect[i].yTop && hitPoint.y <= rect[i].yBottom ) Flag[i] = 1; else Flag[i] = 0; InvalidateRect(hwnd, NULL, TRUE); //break; } return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps); ps.rcPaint.left = rect[i].xLeft; ps.rcPaint.right = rect[i].xRight; ps.rcPaint.top = rect[i].yTop; ps.rcPaint.bottom = rect[i].yBottom; hBrush = (HBRUSH)GetStockObject (GRAY_BRUSH); if (Flag[i] == 1) //如果鼠标位置在矩形框内,将刷子选进设备环境里面 SelectObject(hdc, hBrush); hPen = CreatePen (PS_SOLID, 1, RGB(255,0,0)); SelectObject (hdc, hPen); rect[0].xLeft = 400 ; rect[0].xRight = 420 ; rect[0].yTop = 210 ; rect[0].yBottom = 300 ; Rectangle(hdc, rect[0].xLeft, rect[0].yTop, rect[0].xRight, rect[0].yBottom); for (i = 1; i <NUM; i++) { rect[i].xLeft = rect[i-1].xLeft + 20 ; rect[i].xRight = rect[i-1].xRight + 20 ; rect[i].yTop = rect[0].yTop ; rect[i].yBottom = rect[0].yBottom ; Rectangle(hdc, rect[i].xLeft, rect[i].yTop, rect[i].xRight, rect[i].yBottom); } DeleteObject(hPen); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

下面来看一个这个处理鼠标移动的操作:

case WM_MOUSEMOVE: hitPoint.x = LOWORD(lParam); hitPoint.y = HIWORD(lParam); for (i = 0; i < NUM; i++) { if (hitPoint.x >= rect[i].xLeft && hitPoint.x <= rect[i].xRight && hitPoint.y >= rect[i].yTop && hitPoint.y <= rect[i].yBottom ) Flag[i] = 1; else Flag[i] = 0; InvalidateRect(hwnd, NULL, TRUE); break; } return 0;
一运行问题就来了:只有当鼠标移到第一个矩形的时候才会产生效果,而移到后面9个的时候根本没有产生任何效果!!

我把上面for 循环的 初始条件的  i=0  改成  i=1,这下子更加糟糕了:连第一个矩形都不能产生效果了。看来问题就是在这里了。

那么为什么会不起作用呢?

向华哥请教后,终于发现端倪了:

if (Flag[i] == 1) SelectObject(hdc, hBrush);

我是什么时候把刷子的句柄选入设备环境里面的呢? 就是上面的当  Flag[i] == 1 的时候 ,一旦选入了以后,那么后面所有的矩形绘制的时候用的都是灰色的刷子。

所以首先在WM_PAINT消息里面 添加选择刷子的消息:

for (i = 1; i <NUM; i++)
{

if (Flag[i] == 1)

SelectObject(hdc, hBrush);

rect[i].xLeft    = rect[i-1].xLeft  + 20   ;
 rect[i].xRight   = rect[i-1].xRight + 20   ;
 rect[i].yTop     = rect[0].yTop            ;
 rect[i].yBottom  = rect[0].yBottom         ;
 Rectangle(hdc, rect[i].xLeft, rect[i].yTop, rect[i].xRight, rect[i].yBottom);
}

但是麻烦又来了:如果第i个是灰色的,那么从第i+1个开始后面的所有矩形都变成灰色的了由于发送了10条重绘消息,说明鼠标移动到某个点的时候整个屏幕刷新了10次!!相当于10个矩形总共画了10次!!现在问题应该很明显了:重新绘制出来的窗口把原来的窗口效果给覆盖掉了,如果说原来第i次第i个矩形是灰色的,那么第i+1次的时候又被覆盖成白色的了!!!

而且我的i设置的时候不是全局变量,所以每一个进入VM_PAINT消息的时候i都是0

好了,错误发现以后,我们就可以改正了。首先是逻辑上的修正:

每次重新绘制整个窗口的时候都先把10个矩形画出来,然后在根据鼠标移动传过来的信息判断哪一个矩形应该被重画。

逻辑清楚了以后,写起来就简单了。

我把(一)中的声音效果再加进来,再添加鼠标左键点击发出声音,最终的代码如下:

#include <windows.h> #include <math.h> #include <mmsystem.h> #pragma comment(lib, "WINMM.LIB") #define NUM 10 struct own_rectangle{ int xLeft ; int xRight ; int yTop ; int yBottom ; }rect[NUM]; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("piano demo by mouse"); HWND hwnd; MSG msg; 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.lpszClassName = szAppName; wndclass.lpszMenuName = NULL; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0; } hwnd = CreateWindow (szAppName, TEXT("Piano Demo Using Mouse"), 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) { TCHAR str1[100], str2[100], str_i[10]; static int cxClient, cyClient; static int Flag[NUM] ={0,0,0,0,0,0,0,0,0,0}; HDC hdc; static int i = 0; int j = 0; PAINTSTRUCT ps; //ps数组里面存放了RECT,用来重绘客户区的位置 POINT hitPoint; int xCornerEllipse; int yCornerEllipse; int xStart = 200, yStart = 100, xEnd = 100, yEnd = 300; HBRUSH hBrush; HPEN hPen; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_MOUSEMOVE: hitPoint.x = LOWORD(lParam); hitPoint.y = HIWORD(lParam); for (i = 0; i < NUM; i++) { if (hitPoint.x >= rect[i].xLeft && hitPoint.x <= rect[i].xRight && hitPoint.y >= rect[i].yTop && hitPoint.y <= rect[i].yBottom ) { Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); break; } } if (NUM == i) InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_LBUTTONDOWN: { hitPoint.x = LOWORD(lParam); hitPoint.y = HIWORD(lParam); for (i = 0; i < NUM; i++) { if (hitPoint.x >= rect[i].xLeft && hitPoint.x <= rect[i].xRight && hitPoint.y >= rect[i].yTop && hitPoint.y <= rect[i].yBottom ) { _itow(i+1, str_i, 10); wsprintfW(str1, TEXT("close %s.mp3"),str_i); wsprintfW(str2, TEXT("play %s.mp3"),str_i); mciSendString(str1, NULL, 0, NULL); mciSendString(str2, NULL, 0, NULL); break; } } } break; case WM_PAINT: hdc = BeginPaint (hwnd, &ps); hPen = CreatePen (PS_SOLID, 1, RGB(255,0,0)); SelectObject (hdc, hPen); //hBrush = (HBRUSH)GetStockObject (GRAY_BRUSH); rect[0].xLeft = 400 ; rect[0].xRight = 420 ; rect[0].yTop = 210 ; rect[0].yBottom = 300 ; Rectangle(hdc, rect[0].xLeft, rect[0].yTop, rect[0].xRight, rect[0].yBottom); for (j = 1; j < NUM; j++) { rect[j].xLeft = rect[j-1].xLeft + 20 ; rect[j].xRight = rect[j-1].xRight + 20 ; rect[j].yTop = rect[0].yTop ; rect[j].yBottom = rect[0].yBottom ; Rectangle(hdc, rect[j].xLeft, rect[j].yTop, rect[j].xRight, rect[j].yBottom); } if (Flag[i] == 1){ SelectObject(hdc, (HBRUSH)GetStockObject (GRAY_BRUSH)); Rectangle(hdc, rect[i].xLeft, rect[i].yTop, rect[i].xRight, rect[i].yBottom); } else if (NUM == i){ SelectObject(hdc, (HBRUSH)GetStockObject (WHITE_BRUSH)); Rectangle(hdc, rect[i].xLeft, rect[i].yTop, rect[i].xRight, rect[i].yBottom); } DeleteObject(hPen); EndPaint(hwnd, &ps); return 0; case WM_KEYDOWN: switch(wParam) { case 0x31: i = 0; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 1.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 1.mp3"), NULL, 0, NULL); break; case 0x32: i = 1; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 2.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 2.mp3"), NULL, 0, NULL); break; case 0x33: i = 2; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 3.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 3.mp3"), NULL, 0, NULL); break; case 0x34: i = 3; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 4.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 4.mp3"), NULL, 0, NULL); break; case 0x35: i = 4; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 5.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 5.mp3"), NULL, 0, NULL); break; case 0x36: i = 5; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 6.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 6.mp3"), NULL, 0, NULL); break; case 0x37: i = 6; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 7.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 7.mp3"), NULL, 0, NULL); break; case 0x38: i = 7; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 8.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 8.mp3"), NULL, 0, NULL); break; case 0x39: i = 8; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 9.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 9.mp3"), NULL, 0, NULL); break; case 0x30: i = 9; Flag[i] = 1; InvalidateRect(hwnd, NULL, TRUE); mciSendString(TEXT("close 10.mp3"), NULL, 0, NULL); mciSendString(TEXT("play 10.mp3"), NULL, 0, NULL); break; } return 0; case WM_DESTROY: PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

转载于:https://www.cnblogs.com/magicbox/archive/2012/01/11/2363894.html

windows SDK模拟游戏钢琴的实现(二)相关推荐

  1. windows SDK模拟游戏钢琴的实现(一)

    最近想做一个模拟钢琴的小软件,想做个既有键盘接口又有鼠标接口的小软件.所涉及到的知识点如下: 1.有关键盘的知识 2.有关鼠标的知识 3.GDI的知识 4.媒体播放函数的有关知识 因为这几天也正好在看 ...

  2. Kinect for Windows SDK v2.0 开发笔记 (十二) 高清面部帧(3) 面部模型(2D)

     (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,因为SDK未完成,不附上函数/方法/接口的超链接. 是的, ...

  3. 《模拟飞行入坑(二)P3D SDK环境搭建及CHM文件转化为html》

    SDK包下载 官网下载地址及文档:https://www.prepar3d.com/support/sdk/ 因为游戏使用的是P3DV4.2的版本,所以SDK优先选择 Prepar3D_v4_SDK_ ...

  4. 开发Windows贪吃蛇游戏——(二)代码实现

    目录 前言 窗体部分 Frame部分 声明全局变量 Panel的初始化 startGame方法 paintComponent方法 drawGame方法 newSnake方法 newFood方法 mov ...

  5. [译]Kinect for Windows SDK开发入门(二):基础知识 上

    上篇文章介绍了Kinect开发的环境配置,这篇文章和下一篇文章将介绍Kinect开发的基本知识,为深入研究Kinect for Windows SDK做好基础. 每一个Kinect应用都有一些基本元素 ...

  6. [译]Kinect for Windows SDK开发入门(八):骨骼追踪进阶 上

    前7篇文件我们介绍了Kinect SDK中各种传感器的各种基本知识,我们用实验的方式演示了这些基本对象和方法的如何使用,这些都是Kinect开发最基本的知识.了解了这些基本知识后,就可以开发出一个基于 ...

  7. Kinect for Windows SDK开发入门

    Kinect for Windows SDK开发入门(一):开发环境配置 首先来看一下Kinect设备: 1. Kinect设备 黑色的Kinect设备如下图:基座和感应器之间有一个电动的马达,通过程 ...

  8. 计算机一级的window试题,一级WINDOWS笔试模拟试题及答案(一)

    一级WINDOWS笔试模拟试题及答案(一) 2010-09-09 16:07:00 无忧考网 [ 字体:小 中 大 ] [ 文档预览 ] [ 文档下载 ] 一级WINDOWS笔试模拟试题及答案(一) ...

  9. C++模拟游戏中鼠标点击和键盘按键

    游戏中模拟键盘输入,有时回被系统屏蔽,Java等语言都试过很多方法,好像都没用,所以下面给出一种C++实现方法 #include <iostream> #include <windo ...

最新文章

  1. 一块GPU如何模拟猴子大脑?
  2. Linux System Programming --Chapter Two
  3. 朴素贝叶斯-垃圾邮件分类实现
  4. 2020-12-14 Python PyCharm新建项目自动添加介绍和utf-8编码
  5. VSLAM技术框架详述
  6. 程序员过关斩将——搞定秒杀,只需要这几步!!
  7. python3 print
  8. python 2个dict如何合并
  9. LearnOpenGL 模型加载—Assimp
  10. 杭州地铁行业十四五发展可行性及投资机遇研究报告2022版
  11. PHP快速入门指南-基础篇一
  12. Warbler, A Little Birdie To Introduce Your Rails App To Java
  13. 无法加入域--隶属于域、工作组选项为灰色
  14. 闲鱼网站实时监控iphone最新发布信息
  15. 数据库作业 用Python读取Excel 数据 存放到mysql中
  16. 在Linux中安装dnw
  17. 【iOS】调起地图进行导航(系统地图、高德、百度)
  18. WH-1000XM3蓝牙连接笔记本电脑
  19. 计算机人民币货币符号是什么,人民币货币符号-人民币符号究竟是什么?yen;;还是¥? 爱问知识人...
  20. java抢购_java redis 实现抢购秒杀

热门文章

  1. 李宏毅DLHLP.18.BERT and its family.2/2.ELMo,BERT,GPT,XLNet,MASS,BART,UniLM,ELECTRA
  2. iOS-获取手机唯一标识符(获取苹果手机IMEI,获取苹果手机MAC)
  3. 【数据挖掘】技术点总结
  4. Ufida U8v10.1 安装到sqlserver2008R2 故障转移集群
  5. 第十章:使用MapKit开发地图服务
  6. Android MediaProjection截屏录屏-适配AndroidQ以上版本
  7. Java与Python中的正则匹配
  8. (0)Lora及LoraWAN
  9. 自动化运维工具ansible的安装管理以及模块介绍
  10. 工业路由器油田无线监控