环境:Desktop Qt 5.4.1 MSVC2013 32bit

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

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

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

12
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);SetWidgetBorderless(this);

SetWidgetBorderless的实现如下:

1234567891011121314
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 类,内容如下:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
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 方法:

12345678910
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自带方法即可。

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

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

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

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

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

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

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

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

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

  3. .net mvc mssql easyui treegrid 及时 编辑 ,支持拖拽

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

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

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

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

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

  6. WPF.UIShell UIFramework之自定义窗口的深度技术 - 模态闪动(Blink)、窗口四边拖拽支持(WmNCHitTest)、自定义最大化位置和大小(WmGetMinMaxInfo)

    无论是在工作和学习中使用WPF时,我们通常都会接触到CustomControl,今天我们就CustomWindow之后的一些边角技术进行探讨和剖析. 窗口(对话框)模态闪动(Blink) 自定义窗口的 ...

  7. WinForm支持拖拽效果

    有一个MSDN客户提问在WinForm中如何实现拖拽效果——比如在WinForm中有一个Button,我要实现的效果是拖拽这个Button到目标位置后生成一个该控件的副本. 其实这个操作主要分成三步走 ...

  8. C# 图片盖章功能实现,支持拖拽-旋转-放缩-保存

    实现图片盖章功能,在图片上点击,增加“图章”小图片,可以拖拽“图章”到任意位置,也可以点击图章右下角园框,令图片跟着鼠标旋转和放缩. 操作方法:1.点击增加“图章”2.选中移动图标3.点中右下角放缩旋 ...

  9. 原生JS实现弹出窗口的拖拽

    上一篇说了一下弹出窗口功能的实现思路,一般情况下紧接着就会需要做到弹窗的移动,当然现在有很插件.库比如hammer可以使用,效率也非常好.但我觉得还是有必要了解一下原生JS的实现思路及方式,如下: 思 ...

随机推荐

  1. struts2国际化

    struts2国际化 1:什么是国际化? 国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式.它要求从产品中抽离所有的与语言,国家/地区和文化相关的元素 ...

  2. Webpack学习笔记一:What is webpack

      #,Loaders干嘛的,webpack can only process JavaScript natively, but loaders are used to transform other ...

  3. C#窗体无法接受Keydown事件

    问题一描述:当新建一个窗体时,添加KeyDown事件后,会正常处理,但是当添加有控件时,比如Button,TextBox,不会触发窗体的KeyDown事件,也没有调用KeyDown事件的处理程序. 原 ...

  4. 前端开发教程:使用 CSS3 Transforms 构建圆形导航

    在本教程中我将告诉你如何使用 CSS 变换来创建圆形导航.教程逐一讲解实现这个样式将要涉及一些基本的数学知识并配合 CSS 变换来创建这些样式.不过不用担心,这里用到的数学知识真的是很简单的.教程使用 ...

  5. jdk源码分析之ArrayList

    ArrayList关键属性分析 ArrayList采用Object数组来存储数据 /** * The array buffer into which the elements of the Array ...

  6. java连接mysql :No Suitable Driver Found For Jdbc 解决方法

    今天出现编码出现了No suitable driver found for jdbc,又是找遍了网上的资料,基本上都说是以下个问题:    一是:连接URL格式出现了问题(Connection con ...

  7. hive数据库的一些应用

    1.创建表格create table usr_info(mob string,reason string,tag string) row format delimited fields termina ...

  8. [leetcode]_Merge Two Sorted Lists

    题目:合并两个有序单链表 思路:一开始想复杂了,以为必须在原链表上修改(绕来绕去还AC了,但是思路相当绕),其实没有,按照正常地合并两个数组同样的方法也对. 代码: public ListNode m ...

  9. 10.10 dos实验

    一. 实验目的 (1)认识DOS: (2)掌握命令解释程序的原理: (3)掌握简单的DOS调用方法: (4)掌握C语言编程初步. 二. 实验内容和要求 编写类似于DOS,UNIX的命令行解释程序 (1 ...

  10. bzoj 3781 小B的询问(莫队算法)

    [题意] 若干个询问sigma{ cnt[i]^2 } cnt[i]表示i在[l,r]内的出现次数. [思路] 莫队算法,裸题. 一个cnt数组即可维护插入与删除. [代码] #include< ...