`
java-mans
  • 浏览: 11461637 次
文章分类
社区版块
存档分类
最新评论

windows程序设计(15):对比两种鼠标命中测试

 
阅读更多

先看第一种的程序:

/*-------------------------------------------------
   CHECKER1.C -- Mouse Hit-Test Demo Program No. 1
			  (c) Charles Petzold, 1998
  -------------------------------------------------*/

#include <windows.h>

#define DIVISIONS 5

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR  szCmdLine, int iCmdShow)
{
	
	
	static TCHAR	szAppName[] = TEXT ("Checker1") ;
	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.lpszMenuName	= NULL ;
	wndclass.lpszClassName	= szAppName ;
	

	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
				  szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Checker1 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 BOOL fState[DIVISIONS][DIVISIONS] ;
	//每个格子的大小
	static int  cxBlock, cyBlock ;
	HDC			hdc ;
	int			x, y ;
	PAINTSTRUCT ps ;
	//每个格子耳朵位置
	RECT		rect ;
	
	switch (message)
	{
	case WM_SIZE :
		//获取格子的大小
		cxBlock = LOWORD (lParam) / DIVISIONS ;
		cyBlock = HIWORD (lParam) / DIVISIONS ;
		return 0 ;
		
	case WM_LBUTTONDOWN :
		//点在哪个格子里
		x = LOWORD (lParam) / cxBlock ;
		y = HIWORD (lParam) / cyBlock ;
		
		//防止意外发生
		if (x < DIVISIONS && y < DIVISIONS)
		{
			fState [x][y] ^= 1 ;
			//获取点击的矩形位置
			rect.left   = x * cxBlock ;
			rect.top    = y * cyBlock ;
			rect.right  = (x + 1) * cxBlock ;
			rect.bottom = (y + 1) * cyBlock ;
			//矩形变为无效,重绘矩形
			InvalidateRect (hwnd, &rect, FALSE) ;
		}
		else
			MessageBeep (0) ;
		return 0 ;
		
	case WM_PAINT :
		hdc = BeginPaint (hwnd, &ps) ;
		
		for (x = 0 ; x < DIVISIONS ; x++)
			for (y = 0 ; y < DIVISIONS ; y++)
			{
				//画矩形
				Rectangle (hdc, x * cxBlock, y * cyBlock,(x + 1) * cxBlock, (y + 1) * cyBlock) ;
				//通过标志位判断是否需要画对角线
				if (fState [x][y])
				{
					//画对角线
					MoveToEx (hdc,  x    * cxBlock,  y    * cyBlock, NULL) ;
					LineTo   (hdc, (x+1) * cxBlock, (y+1) * cyBlock) ;
					MoveToEx (hdc,  x    * cxBlock, (y+1) * cyBlock, NULL) ;
					LineTo   (hdc, (x+1) * cxBlock,  y    * cyBlock) ;
				}
			}
		EndPaint (hwnd, &ps) ;
		return 0 ;
			
	case WM_DESTROY :
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


原理是这样的,每次WM_PAINT消息下,都对把客户区分成5*5个矩形方框,为每个方框建立一个bool类数组,当点击一下方框时该方框的数组改为true,再点击一下,变为false。并保存点击的矩形框的位置。每次点击都会是得方框变为无效,引起WM_PAINT消息,而在该消息下,不管三七二十一,先画出25个矩形框,然后通过数组来判断每个矩形框是否需要打叉。

再看另一种程序:

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

#include <windows.h>

#define DIVISIONS 5

LRESULT CALLBACK WndProc   (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;

TCHAR szChildClass[] = TEXT ("Checker3_Child") ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR szCmdLine, int iCmdShow)
{
	
     static TCHAR szAppName[] = TEXT ("Checker3") ;
     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.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 :
		//用SetWindowWord在窗口结构保留的额外区域中储存一个0值
		SetWindowLong (hwnd, 0, 0) ;	  // on/off flag
		return 0 ;
		
	case WM_LBUTTONDOWN :
		//1 与GetWindowLong (hwnd, 0)的结果求异或
		//如果原来是1,异或结果为0
		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) ;
		//如果为1,画图
		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) ;
}


这个程序就完全是另外一种思路了:在WinMain函数中,注册了两个窗口,第一个窗口就是我们正常使用的。第二个窗口有附加的bite,这个比特是用来保留点击信息的,这样与第一个程序相比,就少使用了标记。

在主窗口的WM_CREATE消息下,创建了25个子窗口;在WM_SIZE消息下,将这些窗口摆放到了特定的位置。

程序的主要工作是在子窗口的响应函数下完成的(注意,这时当你点击客户区时,由于客户区被子窗口覆盖满了,所以消息响应全是子窗口的):
WM_CREATE消息下:SetWindowLong (hwnd, 0, 0) ;函数的作用实际上是给标志位设为0,表示没有打叉;

WM_LBUTTONDOWN消息下:SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0))是将/1 与GetWindowLong (hwnd, 0)的结果求异或,而GetWindowLong返回的,就是你设置的那个值(因为设置和返回的偏移量都为0),。所以如果之前里面设为1(有叉),那么与1异或结果为0(无叉)。

WM_PAINT下就用过GetWindowLong返回结果来判断是否需要画插了。

总体上讲,其实我们并没有判断鼠标到底停留在哪个窗口的上空,而是操作系统替我们完成这个工作。

分享到:
评论

相关推荐

    Windows 程序设计(第5版)(上、下册)--详细书签版

    在《Window程序设计》(第5版)中,这位杰出的“Windows先锋奖”(Windows Pioneer Award)获得者根据最新的Windows操作系统权威技术修订了他的经典著作——再一次演示了基本的Win32程序设计的API核心内容。...

    《Windows程序设计》中文chm版

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息...

    windows程序设计第五版 chm 版本

    《Windows程序设计(第5版 珍藏版)》是一本经典的Windows编程圣经,曾经伴随着近50万Windows程序员步入编程殿堂,成长为IT时代的技术精英。 作为Windows开发人员的必备参考,涵盖基础知识和中高级主题,全面地介绍了...

    windows程序设计(第五版)

    mk:@MSITStore:E:\新建文件夹\Windows程序设计\Windows程序设计(CH).chm:... 2006-5-5 显示和打印 DIB和DDB的结合 16. 调色盘管理器 使用调色盘 调色盘动画 调色盘和真实世界图像 DIB处理链接库 17. 文字和...

    windows程序设计 windows程序设计

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息...

    windows 程序设计.doc

    WINDOWS程序设计选项 9 编写第一个WINDOWS程序 13 2. Unicode简介 20 字符集简史 21 宽字符和C 27 宽字符和WINDOWS 30 3. 窗口和消息 36 自己的窗口 37 WINDOWS程序设计的难点 57 4. 输出文本 59 绘制和更新 ...

    windows 程序设计 CHM

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息...

    Windows 程序设计 chm

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息...

    对比5种页面置换算法的访问命中率

    本实验的程序设计基本上按照实验内容进行。即首先用 srand()和 rand()函数定 义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法 计算出相应的命中率。相关定义如下: 1 数据结构 (1)页面类型 ...

    Windows 程序设计

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息 ...

    收藏多年的Windows程序设计

    字符消息 键盘消息和字符集 插入符号(不是光标) 鼠标 鼠标基础 显示区域鼠标消息 非显示区域鼠标消息 程序中的命中测试 拦截鼠标 鼠标滑轮 定时器 定时器入门 ...

    windows 程序设计

    程式中的命中测试 . 拦截滑鼠 . 滑鼠滑轮 8. 计时器 . 计时器入门 . 计时器的使用:三种方法 . 计时器用於时钟 . 以计时器进行状态报告 9. 子视窗控制项 . 按钮类别 . 控制项与颜色 . 静态类别 . ...

    Windows程序设计 中英文版 包括全书源码

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息 ...

    WINDOWS程序设计CHM格式

    …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 …………………… 宽字符和C …………………… 宽字符和WINDOWS 3. 窗口和消息...

    [Windows程序设计]电子版

    [Windows程序设计]电子版 基础篇 1. 开始 …………………… WINDOWS环境 …………………… WINDOWS程序设计选项 …………………… 编写第一个WINDOWS程序 2.Unicode简介 …………………… 字符集简史 ...

Global site tag (gtag.js) - Google Analytics