WM_NCHITTEST (处理无边框窗口的缩放)

时间:2022-07-21 14:34:49

MSDN对它的解释是:

The WM_NCHITTEST message is sent to a window when the cursor moves, or when a mouse button is pressed or released. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse.

这个消息是当鼠标移动或者有鼠标键按下时候发出的。

Windows用这个消息来做什么? “HITTEST”就是“命中测试”的意思,WM_NCHITTEST消息用来获取鼠标当前命中的位置。

WM_NCHITTEST的消息响应函数会根据鼠标当前的坐标来判断鼠标命中了窗口的哪个部位,消息响应函数的返回值指出了部位,例如它可能会返回HTCAPTION,或者HTCLIENT等。(其返回值有很多,请查阅MSDN)。

为了便于理解,我先描述一下Windows对鼠标键按下的响应流程:

1. 确定鼠标键点击的是哪个窗口。Windows会用表记录当前屏幕上各个窗口的区域坐标,当鼠标驱动程序通知Windows鼠标键按下了,Windows根据鼠标的坐标确定它点击的是哪个窗口。

2. 确定鼠标键点击的是窗口的哪个部位。Windows会向鼠标键点击的窗口发送WM_NCHITTEST消息,来询问鼠标键点击的是窗口的哪个部位。(WM_NCHITTEST的消息响应函数的返回值会通知Windows)。通常来说,WM_NCHITTEST消息是系统来处理的,用户一般不会主动去处理它(也就是说,WM_NCHITTEST的消息响应函数通常采用的是Windows默认的处理函数)。

3. 根据鼠标键点击的部位给窗口发送相应的消息。例如:如果WM_NCHITTEST的消息响应函数的返回值是HTCLIENT,表示鼠标点击的是客户区,则Windows会向窗口发送WM_LBUTTONDOWN消息;如果WM_NCHITTEST的消息响应函数的返回值不是HTCLIENT(可能是HTCAPTION、HTCLOSE、HTMAXBUTTON等),即鼠标点击的是非客户区,Windows就会向窗口发送WM_NCLBUTTONDOWN消息。


下面是利用WM_NCHITTEST处理无边框窗口缩放问题:
响应消息,消息响应函数如下:

LRESULT OnNcHitTest(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
//这里是防止在最大化的时候能缩放窗口(在没有WS_THICKFRAME风格的情况下需要这样处理下)
if (::IsZoomed(m_hWnd))
{
return TRUE;
}

POINT  MousePos;
MousePos.x = GET_X_LPARAM(lParam);
MousePos.y = GET_Y_LPARAM(lParam);
::ScreenToClient(m_hWnd,&MousePos);


RECT rc;
int retn = TRUE;
::GetClientRect(m_hWnd,&rc);
int iWidth = rc.right - rc.left;
int iHeight = rc.bottom - rc.top;
if ( PtInRect(CRect(5, 0, iWidth - 100, 5), MousePos ))  
retn = HTTOP;
else if (PtInRect( CRect(0, 5, 5, iHeight-5), MousePos ))  
retn = HTLEFT;
else if (PtInRect( CRect(iWidth - 5, 25, iWidth, iHeight - 5), MousePos ))  
retn = HTRIGHT;
else if (PtInRect( CRect(5, iHeight - 5, iWidth - 5, iHeight), MousePos ))  
retn  = HTBOTTOM;
else if (PtInRect( CRect( 0, 0, 5, 5 ), MousePos ))
retn = HTTOPLEFT;
else if (PtInRect( CRect( 0, iHeight - 5, 5, iHeight), MousePos ))
retn = HTBOTTOMLEFT;
else if (PtInRect( CRect( iWidth - 5, iHeight - 5, iWidth,  iHeight), MousePos )) 
retn = HTBOTTOMRIGHT;
return retn;
}