当前位置: 首页 > news >正文

[Qt]FrameLessWindow实现调整大小、移动弹窗并具有Aero效果

说明

我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);后无法移动和调整大小,但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小及移动弹窗需求,并且在Windows 10上有Aero效果。
先看一下效果:
FrameLessWindow实现调整大小、移动弹窗并具有Aero效果

代码

大部分参考这个github。然后自己修改了一下,因为github上面的,在设置了qss后怎么也实现不了窗口圆角以阴影。下面修改版的代码可以实现圆角,但也没有阴影,只能在Widget中自己实现阴影了。
如果不需要圆角,github上面的也是会自带阴影的。不用下面的调整版实现方案。

#ifndef AEROMAINWINDOW_H
#define AEROMAINWINDOW_H#include <QMainWindow>class AeroMainWindow : public QMainWindow
{Q_OBJECTpublic:explicit AeroMainWindow(QWidget *parent = nullptr);~AeroMainWindow();//设置是否可以通过鼠标调整窗口大小//if resizeable is set to false, then the window can not be resized by mouse//but still can be resized programticallyvoid setResizeable(bool resizeable=true);bool isResizeable(){return m_bResizeable;}//设置可调整大小区域的宽度,在此区域内,可以使用鼠标调整窗口大小//set border width, inside this aera, window can be resized by mousevoid setResizeableAreaWidth(int width = 5);protected://设置一个标题栏widget,此widget会被当做标题栏对待//set a widget which will be treat as SYSTEM titlebarvoid setTitleBar(QWidget* titlebar);//在标题栏控件内,也可以有子控件如标签控件“label1”,此label1遮盖了标题栏,导致不能通过label1拖动窗口//要解决此问题,使用addIgnoreWidget(label1)//generally, we can add widget say "label1" on titlebar, and it will cover the titlebar under it//as a result, we can not drag and move the MainWindow with this "label1" again//we can fix this by add "label1" to a ignorelist, just call addIgnoreWidget(label1)void addIgnoreWidget(QWidget* widget);bool nativeEvent(const QByteArray &eventType, void *message, long *result);void resizeEvent(QResizeEvent *event);public slots:private slots:void onTitleBarDestroyed();private:QWidget *m_titleBar;QList<QWidget*> m_whiteList;int m_borderWidth;bool m_bResizeable;
};#endif // AEROMAINWINDOW_H
#include "aeromainwindow.h"#include <QGraphicsDropShadowEffect>
#include <QDesktopServices>
#include <QUrl>
#include <QGridLayout>
#include <QStyle>
#include <QDebug>
#include <QPushButton>#ifdef Q_OS_WIN
#include <windows.h>
#include <WinUser.h>
#include <windowsx.h>
#include <dwmapi.h>
#include <objidl.h> // Fixes error C2504: 'IUnknown' : base class undefined
#include <gdiplus.h>
#include <GdiPlusColor.h>
#pragma comment (lib,"Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved external symbol __imp__DwmExtendFrameIntoClientArea
#pragma comment (lib,"user32.lib")
#endifAeroMainWindow::AeroMainWindow(QWidget *parent) :QMainWindow(parent),m_titleBar(Q_NULLPTR),m_borderWidth(5),m_bResizeable(true)
{this->setAttribute(Qt::WA_TranslucentBackground);//设置窗口背景透明this->setWindowFlags(Qt::FramelessWindowHint); //设置无边框窗口this->setResizeable(true);
}AeroMainWindow::~AeroMainWindow()
{
}void AeroMainWindow::setResizeable(bool resizeable)
{bool visible = isVisible();m_bResizeable = resizeable;if (m_bResizeable){setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);//此行代码可以带回Aero效果,同时也带回了标题栏和边框,在nativeEvent()会再次去掉标题栏////this line will get titlebar/thick frame/Aero back, which is exactly what we want//we will get rid of titlebar and thick frame again in nativeEvent() laterHWND hwnd = (HWND)this->winId();DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);}else{setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);HWND hwnd = (HWND)this->winId();DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);::SetWindowLong(hwnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX & ~WS_CAPTION);}//保留一个像素的边框宽度,否则系统不会绘制边框阴影const MARGINS shadow = { 1, 1, 1, 1 };DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);setVisible(visible);
}void AeroMainWindow::setResizeableAreaWidth(int width)
{if (1 > width) width = 1;m_borderWidth = width;
}void AeroMainWindow::setTitleBar(QWidget* titlebar)
{m_titleBar = titlebar;if (!titlebar) return;connect(titlebar, SIGNAL(destroyed(QObject*)), this, SLOT(onTitleBarDestroyed()));
}void AeroMainWindow::onTitleBarDestroyed()
{if (m_titleBar == QObject::sender()){m_titleBar = Q_NULLPTR;}
}void AeroMainWindow::addIgnoreWidget(QWidget* widget)
{if (!widget) return;if (m_whiteList.contains(widget)) return;m_whiteList.append(widget);
}bool AeroMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{MSG* msg = (MSG *)message;switch (msg->message){case WM_NCCALCSIZE:{//this kills the window frame and title bar we added with//WS_THICKFRAME and WS_CAPTION*result = 0;return true;} // WM_NCCALCSIZEcase WM_NCHITTEST:{*result = 0;const LONG border_width = m_borderWidth; //in pixelsRECT winrect;GetWindowRect(HWND(winId()), &winrect);long x = GET_X_LPARAM(msg->lParam);long y = GET_Y_LPARAM(msg->lParam);if(m_bResizeable){bool resizeWidth = minimumWidth() != maximumWidth();bool resizeHeight = minimumHeight() != maximumHeight();if(resizeWidth){//left borderif (x >= winrect.left && x < winrect.left + border_width){*result = HTLEFT;}//right borderif (x < winrect.right && x >= winrect.right - border_width){*result = HTRIGHT;}}if(resizeHeight){//bottom borderif (y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOM;}//top borderif (y >= winrect.top && y < winrect.top + border_width){*result = HTTOP;}}if(resizeWidth && resizeHeight){//bottom left cornerif (x >= winrect.left && x < winrect.left + border_width &&y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOMLEFT;}//bottom right cornerif (x < winrect.right && x >= winrect.right - border_width &&y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOMRIGHT;}//top left cornerif (x >= winrect.left && x < winrect.left + border_width &&y >= winrect.top && y < winrect.top + border_width){*result = HTTOPLEFT;}//top right cornerif (x < winrect.right && x >= winrect.right - border_width &&y >= winrect.top && y < winrect.top + border_width){*result = HTTOPRIGHT;}}}if (0 != *result) return true;//*result still equals 0, that means the cursor locate OUTSIDE the frame area//but it may locate in titlebar areaif (!m_titleBar) return false;//support highdpidouble dpr = this->devicePixelRatioF();QPoint pos = m_titleBar->mapFromGlobal(QPoint(x/dpr,y/dpr));if (!m_titleBar->rect().contains(pos)) return false;QWidget* child = m_titleBar->childAt(pos);if (!child){*result = HTCAPTION;return true;}else{if (m_whiteList.contains(child)){*result = HTCAPTION;return true;}}return false;} // WM_NCHITTESTdefault:return QMainWindow::nativeEvent(eventType, msg, result);}
}void AeroMainWindow::resizeEvent(QResizeEvent *event)
{if (m_titleBar)m_titleBar->setGeometry(QRect(0, 0, this->rect().width(), m_titleBar->rect().height()));QMainWindow::resizeEvent(event);
}

测试代码

生成一个类,继承上面的类。然后实现下面的内容。很简单:

#include "testmainwindow.h"
#include "ui_testmainwindow.h"TestMainWindow::TestMainWindow(QWidget *parent) :AeroMainWindow(parent),ui(new Ui::TestMainWindow)
{ui->setupUi(this);QWidget *titleBar = new QWidget(this);titleBar->setGeometry(QRect(0, 0, this->rect().width(), 25));this->setTitleBar(titleBar);this->setStyleSheet("background-color: red;\border-radius: 8px;");
}TestMainWindow::~TestMainWindow()
{delete ui;
}

相关文章:

[Qt]FrameLessWindow实现调整大小、移动弹窗并具有Aero效果

说明 我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);后无法移动和调整大小&#xff0c;但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小及移动弹窗需求&#xff0c;并且在Windows 10上有Aero效果。 先看一下效果&#xf…...

【API生命周期看护】API日落

一、基本概念 在API的整个生命周期中&#xff0c;不可能是永远不变的。功能可能有变动、服务也可能有升级迭代&#xff0c;这个时候对外的能力入口&#xff1a;API自然也需要改变。 一般来说&#xff0c;API的变动是不可以引入兼容性问题的&#xff0c;也即不管做什么变动&am…...

PHP 使用ThinkPHP实现电子邮件发送示例

文章目录 首先我们需要设置我们的邮箱客户端授权&#xff0c;获取到授权码找到我们的邮箱设置去账号中找到这一堆服务&#xff0c;找到后开启smtp服务开启服务后管理服务 接下来需要去下载相应的第三方类库(我这里使用的是PHPMailer)在thinkPHP中封装一下邮件服务类实际调用效果…...

Leetcode-每日一题【剑指 Offer 18. 删除链表的节点】

题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 注意&#xff1a;此题对比原题有改动 示例 1: 输入: head [4,5,1,9], val 5输出: [4,1,9]解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么在调…...

[LINUX使用] top 命令的使用

COLUMNS150 LINES100 top 序号 是否为启动命令 命令模板 详解 1 no vh 帮助 2 yes -d 0.01 0.01秒的间隔刷新top输出 3 no c COMMAND列切换 4 yes -e [k | m | g | t | p] 以何种计量单位显示内存列 k-kb&#xff0c;m-mb&#xff0c;g-gb&#xff0c;t-t…...

通过redis进行缓存分页,通过SCAN扫描进行缓存更新

问题&#xff1a;当我们要添加缓存时&#xff0c;如果我们用了PageHelper时&#xff0c;PageHelper只会对查询语句有效&#xff08;使用到sql的查询&#xff09;&#xff0c;那么如果我们把查询到的数据都添加到缓存时&#xff0c;就会无法进行分页&#xff1b; 此时我们选择将…...

C#小轮子 Debug,Release,发布模式如何运行不同的代码

文章目录 前言C#运行模式运行模式介绍三种模式区分代码 前言 编译模式和发布模式的代码不一样是非常正常的。比较常见的是数据库不一样。编译测试数据库和发布真实的数据库地址不一样。 C#运行模式 运行模式介绍 运行模式有三种&#xff1a; Debug 不进行优化&#xff0c;…...

【【萌新的STM32 学习-6】】

萌新的STM32 学习-6 BSP 文件夹&#xff0c;用于存放正点原子提供的板级支持包驱动代码&#xff0c;如&#xff1a;LED、蜂鸣器、按键等。 本章我们暂时用不到该文件夹&#xff0c;不过可以先建好备用。 CMSIS 文件夹&#xff0c;用于存放 CMSIS 底层代码&#xff08;ARM 和 ST…...

“深入解析JVM:探索Java虚拟机的工作原理“

标题&#xff1a;深入解析JVM&#xff1a;探索Java虚拟机的工作原理 摘要&#xff1a;本文将深入解析Java虚拟机&#xff08;JVM&#xff09;的工作原理&#xff0c;从字节码到执行过程&#xff0c;从内存模型到垃圾回收机制&#xff0c;逐步剖析JVM的核心组成部分和工作原理。…...

【目标检测系列】YOLOV2解读

为更好理解YOLOv2模型&#xff0c;请先移步&#xff0c;了解YOLOv1后才能更好的理解YOLOv2所做的改进。 前情回顾&#xff1a;【目标检测系列】YOLOV1解读_怀逸%的博客-CSDN博客 背景 通用的目标检测应该具备快速、准确且能过识别各种各样的目标的特点。自从引入神经网络以来&a…...

【深入浅出程序设计竞赛(基础篇)第一章 算法小白从0开始】

深入浅出程序设计竞赛&#xff08;基础篇&#xff09;第一章 算法小白从0开始 第一章 例题例1-1例1-2例1-3例1-4例1-5例1-6例1-7例1-8例1-9例1-10例1-11 第一章 课后习题1-11-21-31-4 第一章 例题 例1-1 #include<iostream> using namespace std;int main(){cout <&…...

openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句

文章目录 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句36.1 语法格式36.2 参数说明36.3 示例 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句 清理表数据&#xff0c;TRUNCATE TABLE用于删除表的数据&#xff0c;但不删除表结构。也可以…...

ChatGPT生成文本检测器算法挑战大赛

ChatGPT生成文本检测器算法挑战大 比赛链接&#xff1a;2023 iFLYTEK A.I.开发者大赛-讯飞开放平台 (xfyun.cn) 1、数据加载和预处理 import numpy as np import pandas as pd from sklearn.model_selection import train_test_split, cross_val_predict from sklearn.linea…...

O2OA开发平台实施入门指南

O2OA&#xff08;翱途&#xff09;开发平台&#xff0c;是一款适用于协同办公系统开发与实施的基础平台&#xff0c;说到底&#xff0c;它也是一款快速开发平台。开发者可以基于平台提供的能力完成门户、流程、信息相关的业务功能开发。 既然定位为开发平台&#xff0c;那么开…...

服装行业多模态算法个性化产品定制方案 | 京东云技术团队

一、项目背景 AI赋能服装设计师&#xff0c;设计好看、好穿、好卖的服装 传统服装行业痛点 • 设计师无法准确捕捉市场趋势&#xff0c;抓住中国潮流 • 上新周期长&#xff0c;高库存滞销风险大 • 基本款居多&#xff0c;难以满足消费者个性化需求 解决方案 • GPT数据…...

MySQL表空间结构与页、区、段的定义

文章目录 一、概念引入1、页2、区3、段 二、页的结构1、File Header2、FIle Trailer 三、区的结构1、分类2、XDES Entry3、XDES Entry链表 四、段的结构五、独立表空间1、FSP_HDR页2、XDES页3、IBUF_BITMAP页4、INODE页5、INDEX页 六、系统表空间 一、概念引入 1、页 InnoDB是…...

RaabitMQ(三) - RabbitMQ队列类型、死信消息与死信队列、懒队列、集群模式、MQ常见消息问题

RabbitMQ队列类型 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选择是否持久化(Durability)以及是否自动删除(Auto delete)两个属性。 Durability有两个选项&#xff0c;Durable和Transient。 Durable表…...

Unity3D GPU Selector/Picker

Unity3D GPU Selector/Picker 一、概述 1.动机 Unity3D中通常情况下使用物理系统进行物体点击选择的基础&#xff0c;对于含大量对象的场景&#xff0c;添加Collider组件会增加内容占用&#xff0c;因此使用基于GPU的点击选择方案 2.实现思路 对于场景的每个物体&#xff0c;…...

灰度非线性变换之c++实现(qt + 不调包)

本章介绍灰度非线性变换&#xff0c;具体内容包括&#xff1a;对数变换、幂次变换、指数变换。他们的共同特点是使用非线性变换关系式进行图像变换。 1.灰度对数变换 变换公式&#xff1a;y a log(1x) / b&#xff0c;其中&#xff0c;a控制曲线的垂直移量&#xff1b;b为正…...

轻量级Web框架Flask

Flask-SQLAlchemy MySQL是免费开源软件&#xff0c;大家可以自行搜索其官网&#xff08;https://www.MySQL.com/downloads/&#xff09; 测试MySQL是否安装成功 在所有程序中&#xff0c;找到MySQL→MySQL Server 5.6下面的命令行工具&#xff0c;然后单击输入密码后回车&am…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql

安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了&#xff0c;系统很多命…...