让Qt的无边框窗口支持拖拽、Aero Snap、窗口阴影等特性

时间:2022-08-28 14:08:59

环境:Desktop Qt 5.4.1 MSVC2013 32bit

需要的库:dwmapi.lib 、user32.lib

需要头文件:<dwmapi.h> 、<windowsx.h>

在要处理的QWidget 构造函数中,添加以下两行:

1
2
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
SetWidgetBorderless(this);

SetWidgetBorderless的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void SetWidgetBorderless(const QWidget *widget)
{
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(widget->winId()); const LONG style = ( WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN );
SetWindowLongPtr(hwnd, GWL_STYLE, style); const MARGINS shadow = {1, 1, 1, 1};
DwmExtendFrameIntoClientArea(hwnd, &shadow); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
#endif
}

这个函数的作用是给无边框窗口加上阴影、Aero Snap以及其他动画特效。

这时窗口还无法手动更改大小,需要更改的话,需要自己实现一个QAbstractNativeEventFilter 类,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
class NativeEventFilter : public QAbstractNativeEventFilter
{
public:
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE
{
#ifdef Q_OS_WIN
if (eventType != "windows_generic_MSG")
return false; MSG* msg = static_cast<MSG*>(message);
QWidget* widget = QWidget::find(reinterpret_cast<WId>(msg->hwnd));
if (!widget)
return false; switch (msg->message) {
case WM_NCCALCSIZE: {
*result = 0;
return true;
} case WM_NCHITTEST: {
const LONG borderWidth = 9;
RECT winrect;
GetWindowRect(msg->hwnd, &winrect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam); // bottom left
if (x >= winrect.left && x < winrect.left + borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMLEFT;
return true;
} // bottom right
if (x < winrect.right && x >= winrect.right - borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMRIGHT;
return true;
} // top left
if (x >= winrect.left && x < winrect.left + borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPLEFT;
return true;
} // top right
if (x < winrect.right && x >= winrect.right - borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPRIGHT;
return true;
} // left
if (x >= winrect.left && x < winrect.left + borderWidth)
{
*result = HTLEFT;
return true;
} // right
if (x < winrect.right && x >= winrect.right - borderWidth)
{
*result = HTRIGHT;
return true;
} // bottom
if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOM;
return true;
} // top
if (y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOP;
return true;
} return false;
}
default:
break;
} return false;
#else
return false;
#endif
}
};

然后在窗口创建之前,使用QApplication::installNativeEventFilter 方法把监听器注册给主程序。

要手动移动窗口位置的话,还要重截QWidget::mousePressEvent 方法:

1
2
3
4
5
6
7
8
9
10
void MyWidget::mousePressEvent(QMouseEvent *ev)
{
QWidget::mousePressEvent(ev);
if (!ev->isAccepted()) {
#ifdef Q_OS_WIN
ReleaseCapture();
SendMessage(reinterpret_cast<HWND>(winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
#endif
}

在实际操作时,有时还需要添加最大化和关闭按扭,这时正常调用QWidget::showMaximized()QWidget::close() 等Qt自带方法即可。

最终实现效果大概是这样:

让Qt的无边框窗口支持拖拽、Aero Snap、窗口阴影等特性

缩放动画、阴影什么的和Windows本地窗口一样。

参考链接:https://github.com/deimos1877/BorderlessWindow

https://blog.yeatse.com/2015/03/01/qt-frameless-window/

让Qt的无边框窗口支持拖拽、Aero Snap、窗口阴影等特性的更多相关文章

  1. winform 窗体设置成无边框、可拖拽、四周圆角

    最近做一个及时通讯系统的登录界面,现在将界面用到的无边框.可拖拽.四周圆角的方法分享如下: 1.无边框的窗体: 把FormBorderStyle的属性设置为none 2.可拖拽:private Poi ...

  2. Qt无边框窗体-最大化时支持拖拽还原

    目录 一.概述 二.效果展示 三.demo制作 1.设计窗体 2.双击放大 四.拖拽 五.相关文章 原文链接:Markdown模板 一.概述 用Qt进行开发界面时,既想要实现友好的用户交互又想界面漂亮 ...

  3. Qt——透明无边框Widget的bug

    Experience 最近在封装一些类的时候,打算做一个窗口框架,能实现拖动.缩放.最大最小化.基本样式等功能,可不慎遇见一件无比蛋疼的事情,QWidget最小化后再恢复正常界面,最小化按钮居然仍处于 ...

  4. jQuery插件之路&lpar;三&rpar;——文件上传(支持拖拽上传)

    好了,这次咱一改往日的作风,就不多说废话了,哈哈.先贴上源代码地址,点击获取.然后直接进入主题啦,当然,如果你觉得我有哪里写的不对或者欠妥的地方,欢迎留言指出.在附上一些代码之前,我们还是先来了解下, ...

  5. GMF Q&amp&semi;A(1)&colon; 如何让palette支持拖拽(DnD)等10则

    1,如何让palette支持拖拽(DnD) 在*PaletteFactory类中,把私有类NodeToolEntry 和LinkToolEntry的基类修改为PaletteToolEntry.并在构造 ...

  6. &period;net mvc mssql easyui treegrid 及时 编辑 ,支持拖拽

    这里提到了,1个问题,怎么扩展 Easyui 参见: http://blog.csdn.net/chenkai6529/article/details/17528833 @{ ViewBag.Titl ...

  7. 一个可以*定制外观、支持拖拽消除的MaterialDesign风格Android BadgeView

    为了尊重作者,先放上链接:https://github.com/qstumn/BadgeView BadgeView 一个可以*定制外观.支持拖拽消除的MaterialDesign风格Android ...

  8. 关于安装了VMware tools后仍然不支持拖拽文件的问题

    我在学校机房里面的redhat4上面安装了VMware tools之后能正常支持拖拽,但是我自己电脑上的却不支持,折腾了好久,网上找了很久也还是没有解决,不过发现了一些问题,总结如下:(当然我总结的这 ...

  9. 让一个view 或者控件不支持拖拽

    让一个view 或者控件不支持拖拽: dragView.userInteractionEnabled = NO;

随机推荐

  1. ruby的加密方法整理(des rsa加密 加签)

    # coding:utf-8require 'openssl'require 'base64'#des加密并且base64编码def des_encrypt des_key, des_text des ...

  2. ember&period;js&colon;使用笔记8 加载测试与集成测试

    emberjs使用的测试工具为qunit.js: 加载:将runner.js添加到Index.html:大致内容: if (window.location.search.indexOf("? ...

  3. JS1-属性操作

    属性操作语法 读操作:获取.找到 元素.属性名 写操作:“添加”.替换.修改 元素.属性名 = 新的值 元素.innerHTML => 读取元素里面所有的html代码 元素.innerHTML ...

  4. UIPickerView&lpar;选择控制器&rpar; 自学之初体验

    UIPickerView 是一个选择器控件, 它可以生成单列的选择器,也可生成多列的选择器,而且开发者完全可以自定义选择项的外观,因此用法非常灵活.UIPickerView 直接继承了 UIView  ...

  5. ZRender源码分析5:Shape绘图详解

    回顾 上一篇说到:ZRender源码分析4:Painter(View层)-中,这次,来补充一下具体的shape 关于热区的边框 以圆形为例: document.addEventListener('DO ...

  6. Ibatis入门基本语法(转) good

    Ibatis入门基本语法 一个项目中在写ibatis中的sql语句时,where user_id in (#user_id_list# ), 运行时总是不行,后来上网查了查,才知道这里不该用#,而应该 ...

  7. 跨域请求,jsonp

    其实跨域请求,只需要在请求的url后面加上callback=?即可. 提供以下两种获取跨域的ajax的写法,都是基于jQuery.都已经成功使用,兼容做到ie7,(ie6未测试);案例地址来自豆瓣开放 ...

  8. 原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现

    在我们日常生活中运动就是必不可少的部分,走路.跑步.打篮球等.在网页交互设计上运动也是必不可少的部分,创建的网站交互设计运动模块有轮播图,下拉菜单,还有各种炫酷的游戏效果都跟运动密切相关.所以很重要, ...

  9. webService的介绍与简单使用

    webService开发项目介绍: 1 Webservice:跨语言跨平台的远程调用技术.Web service 即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术即跨平台远程调用技术. ...

  10. 如何在地址栏(title标签里)和收藏夹里 加上网站的标志ICO、LOGO图片

    第一步:首先你必须要制作一个看起来既清楚又容易辨识的.ico格式的小图片. 我们将图标的大小定义为16x16 像素.此外在制作图形文件的时候,你可能需要把色盘设定成只使用标准的 16 色 Window ...