无边框窗体的拖动以及大小改变的实现方式

本文介绍了如何在去除窗体边框追求扁平化效果时,处理无边框窗体的拖动和大小改变。通过响应WM_NCHITTEST窗口消息,结合Delphi代码示例,实现鼠标在不同区域触发对应操作,如拖动窗体或改变其大小。当有控件覆盖窗体时,可通过在控件中处理WM_NCHITTEST消息并传递给父类来解决无法接收消息的问题。
摘要由CSDN通过智能技术生成

       目前,界面流行扁平化,对于传统的window窗体,我们经常需要去掉窗体的边框,以求视角扁平化的效果。去掉窗体的边框很容易,关键是对于无边框的窗体,我们无法对其进行拖动,也无法通过拖动窗体边缘来改变窗体的大小。通常我们会想到处理鼠标事件来模拟效果,但我们自己手动写代码会麻烦许多。其实window消息中,有个WM_NCHITTEST,普通窗体中,点击标题栏拖动窗口以及拖动窗体边缘改变窗体大小就是通过发送并处理这个消息实现的,我们可以在给窗口添加这个消息的事件响应函数,就可以模拟相应的效果。

   关于WM_NCHITTEST的相关信息,大家可以在网上查到,这里不再介绍。下面的是Delphi中的实现代码。

var

  vPoint: TPoint;

begin

  inherited;

实现 MFC 无边框窗体可以通过以下步骤: 1. 创建一个派生自 CWnd 的类,作为无边框窗口的基类。 2. 重载 OnNcCalcSize 函数,计算非客户区的大小。 3. 重载 OnNcPaint 函数,绘制非客户区的背景和边框。 4. 重载 OnNcLButtonDown 函数,处理鼠标左键按下事件,如果鼠标位于窗口边缘,则将鼠标捕获,并设置窗口大小变化标志。 5. 重载 OnNcLButtonUp 函数,处理鼠标左键释放事件,释放鼠标捕获,并清除窗口大小变化标志。 6. 重载 OnMouseMove 函数,处理鼠标移动事件,如果窗口大小变化标志被设置,则根据鼠标位置改变窗口大小。 下面是一个简单的示例代码: ``` class CMyWnd : public CWnd { public: CMyWnd() { m_bSizing = FALSE; } protected: BOOL m_bSizing; afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) { lpncsp->rgrc[0].left += 2; lpncsp->rgrc[0].top += 2; lpncsp->rgrc[0].right -= 2; lpncsp->rgrc[0].bottom -= 2; } afx_msg void OnNcPaint() { CWindowDC dc(this); CRect rect; GetWindowRect(rect); rect.OffsetRect(-rect.left, -rect.top); rect.DeflateRect(2, 2); dc.FillSolidRect(rect, RGB(192, 192, 192)); dc.Draw3dRect(rect, RGB(0, 0, 0), RGB(0, 0, 0)); } afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point) { if (nHitTest == HTLEFT || nHitTest == HTRIGHT || nHitTest == HTTOP || nHitTest == HTBOTTOM || nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) { SetCapture(); m_bSizing = TRUE; } else { CWnd::OnNcLButtonDown(nHitTest, point); } } afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point) { if (m_bSizing) { ReleaseCapture(); m_bSizing = FALSE; } else { CWnd::OnNcLButtonUp(nHitTest, point); } } afx_msg void OnMouseMove(UINT nFlags, CPoint point) { if (m_bSizing) { CRect rect; GetWindowRect(rect); switch (GetHitTest(point)) { case HTLEFT: rect.left = point.x; break; case HTRIGHT: rect.right = point.x; break; case HTTOP: rect.top = point.y; break; case HTBOTTOM: rect.bottom = point.y; break; case HTTOPLEFT: rect.left = point.x; rect.top = point.y; break; case HTTOPRIGHT: rect.right = point.x; rect.top = point.y; break; case HTBOTTOMLEFT: rect.left = point.x; rect.bottom = point.y; break; case HTBOTTOMRIGHT: rect.right = point.x; rect.bottom = point.y; break; } MoveWindow(rect); } else { CWnd::OnMouseMove(nFlags, point); } } int GetHitTest(CPoint point) { CRect rect; GetWindowRect(rect); int cx = rect.Width() / 3; int cy = rect.Height() / 3; if (point.x < rect.left + cx) { if (point.y < rect.top + cy) { return HTTOPLEFT; } else if (point.y > rect.bottom - cy) { return HTBOTTOMLEFT; } else { return HTLEFT; } } else if (point.x > rect.right - cx) { if (point.y < rect.top + cy) { return HTTOPRIGHT; } else if (point.y > rect.bottom - cy) { return HTBOTTOMRIGHT; } else { return HTRIGHT; } } else { if (point.y < rect.top + cy) { return HTTOP; } else if (point.y > rect.bottom - cy) { return HTBOTTOM; } else { return HTCLIENT; } } } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CMyWnd, CWnd) ON_WM_NCCALCSIZE() ON_WM_NCPAINT() ON_WM_NCLBUTTONDOWN() ON_WM_NCLBUTTONUP() ON_WM_MOUSEMOVE() END_MESSAGE_MAP() ``` 在这个示例代码中,GetHitTest 函数用于确定鼠标位置相对于窗口的位置,以便按照相应的方法改变窗口大小。这个函数是基于窗口分成 9 个区域的思想,每个区域都对应一个鼠标消息。当鼠标位于边缘时,根据鼠标位置判断应该执行哪个消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值