Qt 创建圆角、无边框、有阴影、可拖动的窗口 good
程序窗口的边框,标题栏等是系统管理的,Qt 不能对其进行定制,为了实现定制的边框、标题栏、关闭按钮等,需要把系统默认的边框、标题栏去掉,然后使用 Widget 来模拟它们。这里介绍使用 QSS + QGraphicsDropShadowEffect
来创建圆角、无边框、有阴影、可拖动的窗口。
核心技术要点:
启用 QSS:
setAttribute(Qt::WA_StyledBackground, true)
我们继承 QWidget 实现的 Widget 默认是不启用 QSS 的,为了启用 QSS,需要调用
setAttribute(Qt::WA_StyledBackground, true)
使用
border-radius
创建圆角效果顶级窗口有些 QSS 不生效,例如
border-radius
,所以把要显示圆角的 Widget 上放在另一个顶级 Widget 中,变为非顶级窗口- 顶级窗口需要去掉边框,背景设置为透明
- 去掉边框:
setWindowFlags(Qt::FramelessWindowHint);
- 背景透明:
setAttribute(Qt::WA_TranslucentBackground);
- 去掉边框:
- 使用鼠标事件实现拖动
使用
QGraphicsDropShadowEffect
创建阴影很遗憾,QSS 不支持阴影
使用方法:
FramelessWindow *window = new FramelessWindow(yourWidget)
即可
效果如图:
main.cpp
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
|
#include "FramelessWindow.h"
#include <QDebug>
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建包含主要控件的 Widget
QPushButton *quitButton = new QPushButton("退出");
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(new QLabel("按住我拖动也可以拖动窗口的哦"));
layout->addWidget(new QTextEdit());
layout->addWidget(quitButton);
QWidget *contentWidget = new QWidget();
contentWidget->setLayout(layout);
contentWidget->setObjectName("contentWidget");
contentWidget->setStyleSheet("#contentWidget{background: lightgray; border-radius: 4px;}" // 定制圆角
".QLabel{background: gray;}.QTextEdit{background: white;}");
QObject::connect(quitButton, &QPushButton::clicked, [&app] {
app.quit();
});
// 创建无边框、有阴影、可拖动的窗口
FramelessWindow *window = new FramelessWindow(contentWidget);
window->resize(300, 400);
window->show();
return app.exec();
}
|
FramelessWindow.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#ifndef FRAMELESSWINDOW_H
#define FRAMELESSWINDOW_H
#include <QWidget>
struct FramelessWindowPrivate;
class FramelessWindow : public QWidget {
Q_OBJECT
public:
explicit FramelessWindow(QWidget *contentWidget, QWidget *parent = 0);
~FramelessWindow();
protected:
void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
private:
FramelessWindowPrivate *d;
};
#endif // FRAMELESSWINDOW_H
|
FramelessWindow.cpp
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
|
#include "FramelessWindow.h"
#include <QMouseEvent>
#include <QGridLayout>
#include <QGraphicsDropShadowEffect>
struct FramelessWindowPrivate {
FramelessWindowPrivate(QWidget *contentWidget) : contentWidget(contentWidget) {}
QWidget *contentWidget;
QPoint mousePressedPosition; // 鼠标按下时的坐标
QPoint windowPositionAsDrag; // 鼠标按小时窗口左上角的坐标
};
FramelessWindow::FramelessWindow(QWidget *contentWidget, QWidget *parent) : QWidget(parent) {
setWindowFlags(Qt::FramelessWindowHint); // 去掉边框
setAttribute(Qt::WA_TranslucentBackground); // 背景透明
d = new FramelessWindowPrivate(contentWidget);
// 添加阴影
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(contentWidget);
shadowEffect->setColor(Qt::lightGray);
shadowEffect->setBlurRadius(4); // 阴影的大小
shadowEffect->setOffset(0, 0);
contentWidget->setGraphicsEffect(shadowEffect);
// 添加到窗口中
QGridLayout *lo = new QGridLayout();
lo->addWidget(contentWidget, 0, 0);
lo->setContentsMargins(4, 4, 4, 4); // 注意和阴影大小的协调
setLayout(lo);
}
FramelessWindow::~FramelessWindow() {
delete d;
}
void FramelessWindow::mousePressEvent(QMouseEvent *e) {
// 记录鼠标按下时全局的位置和窗口左上角的位置
d->mousePressedPosition = e->globalPos();
d->windowPositionAsDrag = pos();
}
void FramelessWindow::mouseReleaseEvent(QMouseEvent *e) {
Q_UNUSED(e)
// 鼠标放开始设置鼠标按下的位置为 null,表示鼠标没有被按下
d->mousePressedPosition = QPoint();
}
void FramelessWindow::mouseMoveEvent(QMouseEvent *e) {
if (!d->mousePressedPosition.isNull()) {
// 鼠标按下并且移动时,移动窗口, 相对于鼠标按下时的位置计算,是为了防止误差累积
QPoint delta = e->globalPos() - d->mousePressedPosition;
move(d->windowPositionAsDrag + delta);
}
}
|
思考
还可以使用其他方式实现上面的功能,并且功能也不够丰富,思考下面的问题:
- 使用其他方式实现圆角、阴影,例如:
- 绘图
- 绘制圆角矩形并且实现阴影的算法
- 使用一个圆角带阴影图片,利用九宫格技术绘制(border-image 的原理)
- QSS 的
border-image
- 绘图
- 拖动调整无边框窗口的大小
- 添加标题栏
- 添加最小化、最大化、关闭按钮
http://www.qtdebug.com/qt-frameless-window/
Qt 创建圆角、无边框、有阴影、可拖动的窗口 good的更多相关文章
- 【C#】使用DWM实现无边框窗体阴影或全透窗体
1.无边框窗体阴影,win7(需要开启Aero效果)及以上系统 public class LdwmForm : Form { public LdwmForm() { Initialize(); } / ...
- 初学c# -- 学习笔记(五) winfrom无边框四周阴影
刚用到这个功能,网上扯淡的东西太多了,都是2边阴影,还什么窗口叠加.ps作图啥的,什么玩意.还是老外实在,google找的,无边框窗体,四边透明阴影. public partial class For ...
- Qt中实现无边框的窗体
1 自定义窗体类继承自QWidget 2 在构造函数中设置无边框效果 setWindowFlags(Qt::FramelessWindowHint);//无边框 setAttribute(Qt::WA ...
- Qt:移动无边框窗体(使用Windows的SendMessage)
移动无边框窗体的代码网上很多,其原理都是一样的,但是是有问题的,我这里只是对其修正一下 网上的代码仅仅实现了两个事件 void EditDialog::mousePressEvent(QMouseEv ...
- WINFORM 无边框窗体 阴影与移动
//窗体移动API[DllImport("user32.dll")]public static extern bool ReleaseCapture();[DllImport(&q ...
- C# WPF 建立无边框(标题栏)的登录窗口
前言:笔者最近用c#写WPF做了一个项目,此前未曾做过完整的WPF项目,算是一边学一边用,网上搜了不少资料,效率当然是不敢恭维的,有时会在一些很简单的问题上纠结很长时间,血与泪的教训可不少. 不过,正 ...
- 无边框WPF窗体——允许拖动
https://blog.csdn.net/zjcxhswill/article/details/38646525
- Qt无边框窗体-模拟模态窗体抖动效果
目录 一.概述 二.效果展示 三.功能实现 四.相关文章 原文链接:Qt无边框窗体-模拟模态窗体抖动效果 一.概述 用Qt开发windows客户端界面确实是一大利器,兼顾性能的同时,速度相对来说也不错 ...
- 如何在pyqt中给无边框窗口添加DWM环绕阴影
前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...
随机推荐
- Java 学习(22):Java MySQL 连接
Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL 数据库. Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mys ...
- 《iOS Human Interface Guidelines》——Edit Menu
编辑菜单 用户能够显示一个编辑菜单来在文本视图.网页视图和图像视图运行诸如剪切.粘贴和选择的操作. 你能够调整一些菜单的行为来在你的app中给用户给多的内容控制.比方你能够: 指定哪一个标准菜单命令对 ...
- js进阶正则表达式7点数字字母空格(w d s)(小写表原意,大写表反义)(特殊字符要加反斜杠:var reg22=/\W/g)
js进阶正则表达式7点数字字母空格(w d s)(小写表原意,大写表反义)(特殊字符要加反斜杠:var reg22=/\W/g) 一.总结 1.w d s,word digital space 2.特 ...
- Java8学习之旅2---基于Lambda的JDBC编程
Java8的Lambda表达式确实是一个很好的特性.可是在哪些场合下使用.事实上还是须要细致考虑的.我们当然不能为了使用而使用,而是须要找到切实实用的场合.在JDBC编程中,比如查询语句,首先须要进行 ...
- html常用样式margin、border怎么使用
html常用样式margin.border怎么使用 一.总结 一句话总结:1.margin:auto配合width才能居中:2.border的三个属性依次是边框宽度,边框样式,边框颜色 1.html中 ...
- INT_MIN与溢出
隔了好久没更新了,由于我在学习PL和编译器/解释器的知识. 挺好奇这方面的,由于没有学过相关的课程.所以学起来有点吃力,进展缓慢.所以导致没啥可写的. 今天看到这么一段话: 32位的int型的取值是2 ...
- 树莓派——root用户和sudo
Linux操作系统是一个多用户操作系统,它同意多个用户登录和使用一台计算机. 为了保护计算机(和其它用户的隐私).用户都被限制了能做的事情. 大多数用户都同意执行计算机上大部分程序,而且编辑和保存存放 ...
- erlang app 文件
http://hje.iteye.com/blog/1211734 应用的概念¶ 当我们写了实现特定功能的代码之后,我们可能想将代码转成一个 应用 (application),这是可以作为一个单元启动 ...
- 【t006】三角形分形描绘问题
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 分形是以多种概念和方法相互冲击融合为特征的图形.分形所呈现的无穷玄机和美感引发人们去探索.分形使人们觉悟 ...
- 怎样获取android手机联系人并按字母展示(三)
假设获取contact的头像信息并展示: 怎样依据photoId来获取bitmap: public static Bitmap getContactPhoto(Context context, lon ...