|
楼主 |
发表于 2009-7-30 15:42:00
|
显示全部楼层
Re:关于拖动窗口消息循环停止的问题
以上的程序有问题,因为当鼠标移出窗口的是时候就不能收到消息,因此如果一直按住鼠标不放会使标记一直为true。还有就是在windows xp之前的版本甚至在xp的经典窗口模式下都不会收到WM_NCMOUSELEAVE这条消息,这就使得标记不能及时更新
下面是解决办法
// Message handler.
switch(Message)
{
case WM_NCLBUTTONUP: //鼠标抬起时标记,表示不再拖动,标记设置为false
bNcLButtonDown = false;
return DefWindowProc(Window,Message,wParam,lParam);
case WM_NCRBUTTONDOWN://在标题栏上点击右键不做处理,就是不要弹出系统菜单
return 0;
case WM_NCMOUSELEAVE://鼠标出了标题栏的时候标记也要设置为false,避免鼠标无法定位
bNcLButtonDown = false;
return DefWindowProc(Window,Message,wParam,lParam);
case WM_SYSCOMMAND:
switch( wParam & 0xfff0 )
{
///////////////这里直接返回,避免进入消息循环不出来,使游戏freese////////////////////
//当鼠标在标题栏上按住不放时,系统会发送WM_SYSCOMMAND消息,当DefWindowProc
//收到SC_MOVE后,会发送WM_ENTERSIZEMOVE,这个时候整个消息循环就会停止,直到
//DefWindowProc处理完成返回,所以这个消息不能交给系统处理,直接返回
//SC_KEYMENU消息是按快捷键的时候产生的系统菜单,这时候消息循环也是停止的,直到
//DefWindowProc处理完成返回
//SC_MOUSEMENU消息是鼠标左键点击左上角小图标是产生的系统菜单,同上
case SC_MOVE: //这里是多出来的
::GetCursorPos(&MouseCurPos); //鼠标按下获取当前位置,以便取出现对位置
::GetWindowRect(Window, &WindowCurPos);
WindowDeltaPos.left = MouseCurPos.x - WindowCurPos.left;
WindowDeltaPos.top = MouseCurPos.y - WindowCurPos.top;
bNcLButtonDown = true;
//解决在经典窗口(Windows Classic Style)模式下,收不到WM_NCMOUSELEAVE的问题
if(bNcLButtonDown)
{
TRACKMOUSEEVENT MouseEvent;
MouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
MouseEvent.dwFlags = TME_LEAVE | TME_NONCLIENT;
MouseEvent.hwndTrack = Window;
MouseEvent.dwHoverTime = 0;
::TrackMouseEvent(&MouseEvent);
}
case SC_KEYMENU:
case SC_MOUSEMENU:
if( IsFullscreen() )
return 1;
return 0;
}
case WM_NCHITTEST:
// Prevent the user from selecting the menu in fullscreen mode.
if( IsFullscreen() )
return HTCLIENT;
////////////这里根据鼠标的相对位置设置窗口位置///////////////////////////////////////////////////////
//这里是根据鼠标消息模拟窗口移动的过程
if(bNcLButtonDown)
{
::GetCursorPos(&MouseCurPos);
::GetWindowRect(Window, &WindowCurPos);
WindowCurPos.left = MouseCurPos.x - WindowDeltaPos.left;
WindowCurPos.top = MouseCurPos.y - WindowDeltaPos.top;
::SetWindowPos(Window, HWND_NOTOPMOST, WindowCurPos.left, WindowCurPos.top, WindowCurPos.right, WindowCurPos.bottom, SWP_NOSIZE);
MousePrePos = MouseCurPos;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
return DefWindowProc( Window, Message, wParam, lParam );
}
还有一个重要的地方就是鼠标这种情况下鼠标很容易跑到窗口外边,是拖动窗口显得很费力,这就要是窗口在拖动过程中一直更随鼠标运动,但在消息循环中是不能收到鼠标到窗口外的消息的,所以必须找一个一直循环的地方,使窗口在拖动过程中位置一直跟随鼠标运动,下面这段代码就是防止鼠标跑到窗口外的,因为鼠标往下运动仍在窗口中,消息循环中的代码就可以防止鼠标跑出非客户区,但往上拖动就必须在循环里做,因为收不到鼠标消息,下面这段代码是在游戏循环里做的
//现在这些变量是全局的////////////////////////////////////////
RECT WindowCurPos, WindowDeltaPos; //
POINT MousePrePos, MouseCurPos;
bool bNcLButtonDown = false;
///////////////////////////////////////////////////////////////
if(bNcLButtonDown)
{
::GetCursorPos(&MouseCurPos); //鼠标按下获取当前位置,以便取出现对位置
::GetWindowRect(::GetActiveWindow(), &WindowCurPos);
if(MouseCurPos.y < WindowCurPos.top)
{
WindowCurPos.left = MouseCurPos.x - WindowDeltaPos.left;
WindowCurPos.top = MouseCurPos.y - WindowDeltaPos.top;
//debugf(_T("Current Window Pos X Is %d Y Is %d"),WindowCurPos.left,WindowCurPos.top);
::SetWindowPos(::GetActiveWindow(), HWND_NOTOPMOST, WindowCurPos.left, WindowCurPos.top, WindowCurPos.right, WindowCurPos.bottom, SWP_NOSIZE);
MousePrePos = MouseCurPos;
}
}
|
|