windows程序设计读书笔记三

我想我知道为什么CAD软件中,当鼠标移动很快时,图像会跟不上了。

鼠标移经窗口的客户区时,Windows系统不会为鼠标经过的每个象素位置都产生WM_MOUSEMOVE消息。程序收到的WM_MOUSEMOVE消息个数取决于鼠标硬件和窗口过程处理鼠标移动的速度。换言之,如果消息队列里还未有处理WM_MOUSEMOVE消息,Windows就不会重复向消息队列中添加该消息。


鼠标的捕获如何实现?

       让我想起了以前写运控程序时的 每个轴的点动实现。比如按下X+按钮时,X轴运动,松开X+按钮时,X轴停止。当时实现的方法是重写PreTranslateMessage函数。不过关于PreTranslateMessage的内部机制还没搞清。

1、 毕竟 产生message的当前句柄应该是鼠标所在的位置的程序的。所以当鼠标离开按钮或窗口时,系统得到的鼠标消息 hwnd字段应该为NULL。为什么这么认为?假设有两个窗口,在第一个窗口上按下鼠标后,移动到第二个窗口上,第二个窗口并没有因为鼠标在它上面而被激活。(这时系统还是能得到鼠标消息的,但是没有程序响应了。)

2、如果hwnd字段为NULL,以下程序就无效,事实以下程序是可用的。

3、这是MFC CWnd的虚函数。WinApi里没有的。如何理解其工作机制先扔一边吧,看内部代码还没看出所以然。

BOOL CLeadTechMotionDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	
	if (pMsg->message == WM_LBUTTONDOWN)
	{
		if (pMsg->hwnd == GetDlgItem(IDC_BUTTON_X_POSITIVE)->m_hWnd)
		{
			// 按钮按下 X+
			DMC5480JogAxis(Axis_X, 3000 * nSpeedRate, 300000, 600000, 1);
		}
		else if (pMsg->hwnd == GetDlgItem(IDC_BUTTON_X_NEGATIVE)->m_hWnd)
		{
			// 按钮按下 X-
			DMC5480JogAxis(Axis_X, 3000 * nSpeedRate, 300000, 600000, 0);
		}
	}
	else if (pMsg->message == WM_LBUTTONUP)
	{

		if (pMsg->hwnd == GetDlgItem(IDC_BUTTON_X_POSITIVE)->m_hWnd)
		{
			// 按钮弹起 X+
			DMC5480StopAxis(Axis_X);
		}
		else if (pMsg->hwnd == GetDlgItem(IDC_BUTTON_X_NEGATIVE)->m_hWnd)
		{
			// 按钮弹起 X-
			DMC5480StopAxis(Axis_X);
		}		
	}
	
	return CDialogEx::PreTranslateMessage(pMsg);
}

那么在SDK环境中如何捕获鼠标呢?

SetCapture(hwnd);

调用该函数后,Windows会将所有鼠标消息发送给句柄为 hwnd 的窗口过程。鼠标消息总是以客户区消息的形式出现,即使鼠标位于窗口的非客户区。参数 lParam 仍然表示鼠标在客户区的位置。但是,当鼠标位于客户区外的左方或上方时,这些x和y坐标会出现负值。如果用户想释放鼠标了,则可以调用

        ReleaseCapture();

在MFC CWnd 中也有同名的函数 SetCapture(); ReleaseCapture()。


在这我们注意到,鼠标消息里含有两个坐标1、消息产生位置相对于客户区坐标; 2、消息产生时相对屏幕的左边。

POINT point1, point2;
point1.x = LOWORD(pMsg->lParam);
point1.y = HIWORD(pMsg->lParam);
point2 = pMsg->pt;


关于消息

typedef struct tagMSG { // msg

HWND hwnd; //窗口句柄

UINT message; //消息常量标识符

WPARAM wParam; //32位消息的特定附加信息,具体表示什么处决于message

LPARAM lParam; //32位消息的特定附加信息,具体表示什么处决于message

DWORD time; //消息创建时的时间

POINT pt; //消息创建时的鼠标位置

} MSG;

hwnd 接收消息的32位窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。

message 用于区别其他消息的常量值,这些常量可以是Windows单元中预定义的常量,也可以是自定义的常量。

wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 

lParam 通常是一个指向内存中数据的指针。由于wParam,lParam和指针都是32位的,需要时可以强制类型转换。具体表示什么,与message相关,他们是事先定义好的。

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND  hwndButton[NUM] ;
     static RECT  rect ;
     static TCHAR szTop[]    = TEXT ("message            wParam       lParam"),
                  szUnd[]    = TEXT ("_______            ______       ______"),
                  szFormat[] = TEXT ("%-16s%04X-%04X    %04X-%04X"),
                  szBuffer[50] ;
     static int   cxChar, cyChar ;
     HDC          hdc ;
     PAINTSTRUCT  ps ;
     int          i ;
     
     switch (message)
     {
     case WM_CREATE :
          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;
          
          for (i = 0 ; i < NUM ; i++)
               hwndButton[i] = CreateWindow ( TEXT("button"), 
                                   button[i].szText,
                                   WS_CHILD | WS_VISIBLE | button[i].iStyle,
                                   cxChar, cyChar * (1 + 2 * i),
                                   20 * cxChar, 7 * cyChar / 4,
                                   hwnd, (HMENU) i,
                                   ((LPCREATESTRUCT) lParam)->hInstance, NULL) ;
          return 0 ;

     case WM_SIZE :
          
          return 0 ;
          
     case WM_PAINT :            
          hdc = BeginPaint (hwnd, &ps) ;       
          
          EndPaint (hwnd, &ps) ;
          return 0 ;
          
     case WM_DRAWITEM :
     case WM_COMMAND :
	 
          break ;
          
     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

上述代码中的 WM_CREATE, 是由主程序在 创建主窗口过程中创建的。此时message 的参数

wParam     This parameter is not used.  参数无效。 lParam       A pointer to a  CREATESTRUCT  structure that contains information about the window being created.                     一个指向CREATESTRUCT结构类型的指针。

CREATESTRUCT结构 定义了应用程序中窗口过程的初始化参数

typedef struct tagCREATESTRUCT {  
    LPVOID lpCreateParams;  
    HANDLE hInstance;  
    HMENU hMenu;  
    HWND hwndParent;  
    int cy;  
    int cx;  
    int y;  
    int x;  
    LONG style;  
    LPCSTR lpszName;  
    LPCSTR lpszClass;  
    DWORD dwExStyle;  
} CREATESTRUCT;  
参数
lpCreateParams
指向要用于创建窗口的数据。
hInstance
标识拥有新的窗口中的模块的模块实例句柄。
hMenu
标识要使用新窗口中的菜单。 如果子窗口,将包含整数 id。
hwndParent
将拥有新的窗口的窗口。 此成员是NULL如果新的窗口为顶级窗口。
cy
指定新的窗口的高度。
cx
指定新的窗口的宽度。
y
指定新的窗口的左上角的 y 坐标。 如果新的窗口是一个子窗口; 坐标是相对于父窗口否则坐标是相对于屏幕的原点。
x
指定新的窗口的左上角的 x 坐标。 如果新的窗口是一个子窗口; 坐标是相对于父窗口否则坐标是相对于屏幕的原点。
style
指定新的窗口样式。
lpszName
指向以 null 结尾的字符串,它指定新窗口的名称。
lpszClass
指向以 null 结尾的字符串,它指定新窗口的窗口类名称 ( WNDCLASS结构; 有关详细信息,请参阅Windows SDK)。
dwExStyle
指定扩展样式新窗口。

在创建子窗口时的第10个参数     hlnstance    与窗口相关联的模块实例的句柄

这里就应该是父窗口的 实例的句柄。  那就需要提取lParam指向的结构里的 hInstance成员了 

((LPCREATESTRUCT) lParam)->hInstance


其他操作办法

a、使用全局变量 hInst, 来让窗口过程获得 WinMain的实例句柄。 在WinMain函数中,只需要在主窗口产生之前,简单设置 

static HINSTANCE hInst = hInstance;

 hwndButton[i] = CreateWindow ( TEXT("button"), 
                                   button[i].szText,
                                   WS_CHILD | WS_VISIBLE | button[i].iStyle,
                                   cxChar, cyChar * (1 + 2 * i),
                                   20 * cxChar, 7 * cyChar / 4,
                                   hwnd, (HMENU) i,
                                   hInst, NULL) ;

b、使用GetWindowLong来获得实例句柄。

     GetWindowLong (hwnd, GWL_HINSTANCE)

 hwndButton[i] = CreateWindow ( TEXT("button"), 
                                   button[i].szText,
                                   WS_CHILD | WS_VISIBLE | button[i].iStyle,
                                   cxChar, cyChar * (1 + 2 * i),
                                   20 * cxChar, 7 * cyChar / 4,
                                   hwnd, (HMENU) i,
                                   (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值