一个解决OnNcLButtonUp不能响应消息问题的更好办法

        这几天在写重绘对话框程序,发现好多例子中都是用OnNcLButtonDown来处理系统按钮按下消息,而不是常规的ButtonUp。这样很不爽,鼠标只要一点击按钮,窗口就直接最小化或关闭,这样不符合通常的操作习惯。(通常的Windows应用程序在鼠标键弹起时,才处理事件。)

       当我写程序的时候,才发现,windows不能直接响应OnNcLButtonUp,难怪大家都把事件处理放到OnNcLButtonDown中。在网上搜索了下,原因如下:

        “窗口管理器在处理 OnNcLButtonDown 的时候捕捉了鼠标焦点,即使用了 SetCapture 函数,在捕捉了鼠标焦点后,窗口就不会发送 WM_NCLBUTTONUP 消息,从而不会响应OnNcLButtonUp函数。

有若干种解决办法:

       方法 一:让对话框的OnNcLButtonDown函数不要调用基类的OnNcLButtonDown函数,即,将CDialog::OnNcLButtonDown注释掉,这样带来一个后遗症,不能拖动窗口了!

      方法二:在适当的时候,重新发送WM_NCLBUTTONUP  消息,来执行OnLButtonUp函数。

该解决办法来源:http://blog.csdn.net/yowen/article/details/3992710

在你的CXXDialog中的消息处理函数OnSysCommand()(对WM_SYSCOMMAND的响应)添加下面代码:   
    
  void   CXXXDialog::OnSysCommand(UINT   nID,   LPARAM   lParam)   
  {   
            if(   (nID   &   0xFFF0)   ==   IDM_ABOUTDLG   )   
            {   
                    //   省略...   
            }   
            else   
            {   
                    //   这是本来有的   
                    CDialog::OnSysCommand(nID,   lParam);   
    
                    //   加入下面这2行   
                    if(   (nID   &   0xFFF0)   ==   SC_MOVE   )   
                          PostMessage(WM_NCLBUTTONUP,   nID,   lParam);   
            }   
  }   
        但是,这个方法也有后遗症,就是我们在系统按钮上按下鼠标然后拖动,居然也可以将窗口拖动!

        从上面的这些解决办法中,我们可以隐隐约约看到另一种更好的解决办法。能否将两者结合起来,得到一种完美的结果?答案是肯定的。

        通常我们需要在OnNCLButtonDown函数中,处理鼠标消息,让系统按钮实现按下的效果。如果我们在处理系统按钮按下效果的情况下不去调用基类的OnNCLButtonDown函数,而在没有处理的时候去调用基类的函数,那么,我们就可以实现在按下系统按钮以后得到WM_NCLBUTTONUP消息,而没有按下系统按钮的时候一切照常运行。

以下是算法伪代码:

OnNcLButtonDown(point)
{
if(point  in   closeButtonRect) then closeButtonState = BS_DOWN ,drawCloseButton()
else if(point  in  minButtonRect) then minButtonState = BS_DOWN ,drawMinButton()
else CDialog::OnNcLButtonDown()  //没有处理消息的时候才调用基类
}

OnNcLButtonUp(point)
{
if(point  in  closeButtonRect  and closeButtonState = BS_DOWN) then ExitApplication
else if(point  int minButtonRect and minButtonState = BS_DOWN) then MinWindow
...
CDialog::OnNcLButtonUp()
}







  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下步骤实现: 1. 在 MFC 应用程序中创建一个无边框窗体,可以通过在窗口类的 PreCreateWindow 函数中设置窗口样式来实现,例如: ```c++ BOOL CMyWnd::PreCreateWindow(CREATESTRUCT& cs) { if (!CWnd::PreCreateWindow(cs)) return FALSE; cs.style &= ~WS_BORDER; // 去掉边框样式 cs.style |= WS_THICKFRAME; // 添加调整大小的样式 return TRUE; } ``` 2. 在窗体类中添加以下成员变量: ```c++ BOOL m_bDrag; // 标记是否正在拖动窗体边缘 CPoint m_ptOrigin; // 记录鼠标按下时的位置 ``` 3. 响应 WM_NCHITTEST 消息,判断鼠标位置是否在窗体边缘,并返回对应的鼠标样式: ```c++ UINT CMyWnd::OnNcHitTest(CPoint point) { UINT nHitTest = CWnd::OnNcHitTest(point); if (nHitTest == HTCLIENT) { CRect rect; GetWindowRect(&rect); // 判断鼠标位置是否在窗体边缘 if (point.x < rect.left + 5) nHitTest = HTLEFT; else if (point.x > rect.right - 5) nHitTest = HTRIGHT; if (point.y < rect.top + 5) nHitTest = HTTOP; else if (point.y > rect.bottom - 5) nHitTest = HTBOTTOM; if (point.x < rect.left + 5 && point.y < rect.top + 5) nHitTest = HTTOPLEFT; else if (point.x < rect.left + 5 && point.y > rect.bottom - 5) nHitTest = HTBOTTOMLEFT; else if (point.x > rect.right - 5 && point.y < rect.top + 5) nHitTest = HTTOPRIGHT; else if (point.x > rect.right - 5 && point.y > rect.bottom - 5) nHitTest = HTBOTTOMRIGHT; } return nHitTest; } ``` 4. 响应 WM_NCLBUTTONDOWN 消息,判断鼠标按下的位置是否在窗体边缘,如果是,则记录鼠标按下时的位置,并标记正在拖动边缘: ```c++ void CMyWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) { if (nHitTest == HTLEFT || nHitTest == HTRIGHT || nHitTest == HTTOP || nHitTest == HTBOTTOM || nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) { m_bDrag = TRUE; m_ptOrigin = point; SetCapture(); } CWnd::OnNcLButtonDown(nHitTest, point); } ``` 5. 响应 WM_NCMOUSEMOVE 消息,如果正在拖动边缘,则根据鼠标移动的距离调整窗体大小: ```c++ void CMyWnd::OnNcMouseMove(UINT nHitTest, CPoint point) { if (m_bDrag) { CRect rect; GetWindowRect(&rect); int dx = point.x - m_ptOrigin.x; int dy = point.y - m_ptOrigin.y; switch (nHitTest) { case HTLEFT: rect.left += dx; break; case HTRIGHT: rect.right += dx; break; case HTTOP: rect.top += dy; break; case HTBOTTOM: rect.bottom += dy; break; case HTTOPLEFT: rect.left += dx; rect.top += dy; break; case HTTOPRIGHT: rect.right += dx; rect.top += dy; break; case HTBOTTOMLEFT: rect.left += dx; rect.bottom += dy; break; case HTBOTTOMRIGHT: rect.right += dx; rect.bottom += dy; break; } MoveWindow(&rect); } CWnd::OnNcMouseMove(nHitTest, point); } ``` 6. 响应 WM_NCLBUTTONUP 消息,结束拖动边缘: ```c++ void CMyWnd::OnNcLButtonUp(UINT nHitTest, CPoint point) { if (m_bDrag) { m_bDrag = FALSE; ReleaseCapture(); } CWnd::OnNcLButtonUp(nHitTest, point); } ``` 以上就是实现用鼠标拖动窗体边缘实现窗体大小变化的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值