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 ...
随机推荐
- iOS开发Quzrtz2D:十一:图片截屏以及图片擦除
一:图片截屏:截取的是控制器的view #import "ViewController.h" @interface ViewController () @end @implemen ...
- node转发formdata
router.post('/keUpload', checkLogin, setAccessControlAllow, (req, res, next) => { const busboy = ...
- 【u028】数列的整除性
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式, ...
- [转至云风的博客]开发笔记 (2) :redis 数据库结构设计
接上回,按照我们一期项目的需求,昨天我简单设计了数据库里的数据格式.数据库采用的是 Redis ,我把它看成一个远端的数据结构保存设备.它提供基本的 Key-Value 储存功能,没有层级表.如果需要 ...
- BZOJ 2783 树 - 树上倍增 + 二分
传送门 分析: 对每个点都进行一次二分:将该点作为链的底端,二分链顶端所在的深度,然后倍增找到此点,通过前缀和相减求出链的权值,并更新l,r. code #include<bits/stdc++ ...
- java十五个常用类学习及方法举例
<code class="language-java">import java.util.Scanner; import java.util.Properties; i ...
- PPT之SmartArt功能
在PPT中,我们经常看到这样的漂亮的组合图标: 他们是怎么做出来的呢?其实用ppt自带的SmartArt功能就能做出来了. Tips:SmartArt可以直接先选择组合图标再填文字,还可以写好了文字, ...
- BZOJ 1084 [SCOI2005]最大子矩阵 - 动态规划
传送门 题目大意: 从矩阵中取出k个互不重叠的子矩阵,求最大的和. 题目分析: 对于m=1,直接最大m子段和. 对于m=2: \(dp[i][j][k]\)表示扫描到第一列i和第2列j时选取了k个矩阵 ...
- Atititjs javascript异常处理机制java异常转换.js exception process
Atititjs javascript异常处理机制java异常的转换.js exception process 1. javascript异常处理机制 Throw str Not throw erro ...
- 利用WPF建立自己的3d gis软件(非axhost方式)(二)基础状态切换
原文:利用WPF建立自己的3d gis软件(非axhost方式)(二)基础状态切换 先下载SDK:https://pan.baidu.com/s/1M9kBS6ouUwLfrt0zV0bPew 密 ...