7,鼠标学习三——焦点切换

继《鼠标学习二》中的矩形块绘制,当时采用的是坐标转换的方式。


这次用一种新的绘图方式即子窗口,对,就是用25个子窗口来表示矩形。这样实现了将客户区划分成几个更小的逻辑区域。每个子窗口有属于自己的句柄,窗口过程和客户区。每个子窗口过程只接受与自身窗口有关的鼠标消息。

tips:鼠标消息参数lParam中包含的坐标是相当于子窗口客户区左上角的,而不是父窗口。


那么在两个窗口之间,窗口的焦点如何确定和切换呢?


示例:

#include <windows.h>

#define DIVISIONS 5

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

int idFocus=0;
TCHAR szChildClass[]=TEXT("Check3_Child");

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Check3") ;
     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 ("check3 mouse ht 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),              //子id,这里简单的设定为x和y的组合
				(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_SETFOCUS:
		SetFocus(GetDlgItem(hwnd,idFocus));   //父窗口句柄和子控件id,即可获得子控件句柄
		return 0;

	case WM_KEYDOWN:							
		x=idFocus &0xFF;						//只取低八位  0xff=00000000 00000000 00000000 11111111,就是这么巧妙,刚刚好
		y=idFocus >>8;							//右移八位,将上一个焦点id转换为实际坐标

		switch(wParam)
		{
		case VK_UP:	y--;				break;
		case VK_DOWN:	y++;				break;
		case VK_LEFT:	x--;				break;
		case VK_RIGHT:	x++;				break;
		case VK_HOME:	x=y=0;				break;
		case VK_END:	x=y=DIVISIONS-1;	break;
		default:		return 0;
		}

		x=(x+DIVISIONS)%DIVISIONS;
		y=(y+DIVISIONS)%DIVISIONS;                        //处理负数的情况

		idFocus=y<<8 |x;							//相或运算
		SetFocus(GetDlgItem(hwnd,idFocus));              //当初设定的时候,根据实际坐标在移位而成的
		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);
		return 0;

	<span style="color:#FF0000;">case WM_KEYDOWN:
		//虽然父子窗口都处理键盘消息,但对于enter和space键才将击键消息给子窗口处理,反之,给父窗口
		if(wParam!=VK_RETURN && wParam!=VK_SPACE)                                
		{
			 SendMessage(GetParent(hwnd),message,wParam,lParam);              //也有切换焦点的意思
 			return 0;
 		}</span>
		

	  case WM_LBUTTONDOWN:								//WM_KEYDOWN不通就直接跳到下一个
 		SetWindowLong(hwnd,0,1^GetWindowLong(hwnd,0));    //取得的是额外窗口内存中的值
		 InvalidateRect(hwnd,NULL,FALSE);
 		return 0;

	  case WM_SETFOCUS:
 		idFocus=GetWindowLong(hwnd,GWL_ID);

	  case WM_KILLFOCUS:
 		InvalidateRect(hwnd,NULL,TRUE);
		  return 0;

	 case WM_PAINT:
		  hdc=BeginPaint(hwnd,&ps);

 		GetClientRect(hwnd,&rect);
  		Rectangle(hdc,0,0,rect.right,rect.bottom);  //当前矩形就是一个子窗口,所以从起点(0,0)

		  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);
		 }

		<span style="color:#FF6600;"><span style="color:#000000;"><span style="color:#000099;">if(hwnd==GetFocus())    </span>               /<span style="background-color: rgb(255, 0, 0);">/判断焦点在子窗口还是父窗口</span>
		{
			rect.left+=rect.left/10;
			rect.right-=rect.left;
			rect.top+=rect.bottom/10;
			rect.bottom-=rect.top;

			SelectObject(hdc,GetStockObject(NULL_BRUSH));
			SelectObject(hdc,CreatePen(PS_DASH,0,0));
			Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);
			DeleteObject(SelectObject(hdc,GetStockObject(BLACK_PEN)));
		}</span>
		<span style="color:#000000;">EndPaint(hwnd,&ps);</span>
		<span style="color:#000000;">return 0;</span></span>
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}


由此可见,窗口焦点的切换是通过发送消息到另一个窗口来实现的,因为同一应用程序公用一个消息队列,



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值