Qt——界面美化 QSS
文章目录
- 界面美化 QSS
- 全局样式
- 样式和代码分离
- 选择器
- 类型选择器
- 类选择器
- ID选择器
- 并集选择器
- 子控件选择器
- 伪类选择器
- 渐变色
- 线性渐变
- 径向渐变
- 盒子模型 Box Model
- 样例
- 修改复选框样式
- 修改单行编辑框样式
- 实现一个简单的登陆界面
- QFrame 基本功能
- 绘图
- 绘制形状
- 线段
- 矩形
- 圆
- 文字
- 图片
界面美化 QSS
类似于网页前端的CSS,可以对界面的各种样式进行设置
需要注意,如果QSS和C++代码同时对同一个控件的同一个属性进行了设置,那么QSS的优先级更高
QSS 基本格式:
选择器 {属性名:属性值;
}
例如,将窗口内所有的QPushBUtton
的文本设置成红色:
#include "widget.h"#include "./ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ui->pushButton->setStyleSheet("QPushButton {color : rgb(200, 0, 100);}");
}Widget::~Widget() { delete ui; }
设置样式的时候,是可以指定某个控件来设置的。指定控件之后,此时的样式就会针对这个指定的控件和这个控件的子控件同时生效
例如:
#include "widget.h"#include "./ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);this->setStyleSheet("QPushButton {color : rgb(200, 0, 100);}");
}Widget::~Widget() { delete ui; }
全局样式
通过main
函数内部构造的QApplication
类,进行全局样式设置
- 如果设置了全局样式,然后在某个控件里面又设置了新的样式(不冲突),那么这个控件的样式就会叠加。即层叠性
- 如果设置了全局样式,然后在某个控件里面又设置了同样的的样式,那么局部样式就会覆盖全局样式。即局部样式优先级高于全局样式
- 所以,实际开发中,就可以设置通用的全局样式,来统一风格。如果需要对界面的某个控件进行微调,就可以使用局部样式
例如:
#include <QApplication>#include "widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;a.setStyleSheet("QPushButton {color : green;}");w.show();return a.exec();
}// widget.cpp
#include "widget.h"#include "./ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ui->pushButton_1->setStyleSheet("background-color : white;"); // 叠加性ui->pushButton_2->setStyleSheet("color : rgb(200, 0, 100);}"); // 局部样式优先级高于全局样式
}Widget::~Widget() { delete ui; }
样式和代码分离
如果涉及到的样式比较多,那么将其和C++代码混合明显是不合适的。
我们可以把样式代码拎出来,放到单独的文件中,后续可以直接让C++代码来读取并加载文件内容
Qt Designer
中直接集成了上述功能,允许我们把样式直接写到 **.ui
**文件里,并支持实时预览
选择器
选择器 | 示例 | 说明 |
---|---|---|
全局选择器 | * | 选择所有的 widget. |
类型选择器 (type selector) | QPushButton | 选择所有的 QPushButton 和 其子类 的控件. |
类选择器 (class selector) | .QPushButton | 选择所有的 QPushButton 的控件. 不会选择子类. |
ID 选择器 | #pushButton_2 | 选择 objectName 为 pushButton_2 的控件. |
后代选择器 | QDialog QPushButton | 选择 QDialog 的所有后代(子控件, 孙子控件等等) 中的 QPushButton. |
子选择器 | QDialog > QPushButton | 选择 QDialog 的所有子控件中的 QPushButton. |
并集选择器 | QPushButton, QLineEdit, QComboBox | 选择 QPushButton, QLineEdit, QComboBox 这三种控件. (即接下来的样式会针对这三种控件都生效). |
类型选择器
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style = "QWidget {color : rgb(200, 50, 100);}";ui->layoutWidget->setStyleSheet(style);
}
通过类型选择器,将layoutWidget
下的,所有QWidget
及其子类的控件的文本设置颜色
效果:
类选择器
类选择器和类型选择器的区别是,类选择器不会选择指定控件类型的子类
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style = ".QWidget {color : rgb(200, 50, 100);}";ui->layoutWidget->setStyleSheet(style);
}
通过类选择器,将layoutWidget
下的QWidget
类型的控件的文本设置颜色
效果:
ID选择器
ID选择器只针**对传入的****objectName
**的空间生效
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style = "#pushButton_1 {color : rgb(200, 50, 100);}";ui->layoutWidget->setStyleSheet(style);
}
使用ID选择器,对objectName
为pushButton_1
的控件,设置字体颜色
效果:
并集选择器
通过传入多个类型,样式会对传入的所有类型生效
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style = "QPushButton, QLineEdit {color : rgb(200, 50, 100);}";ui->layoutWidget->setStyleSheet(style);
}
通过并集选择器,将layoutWidget
下的QPushButton
和QLineEdit
类型的控件设置字体颜色
效果:
子控件选择器
有些控件内部包含了多个“子控件“。比如QComboBox
的下拉后的面板
可以通过子控件选择器::
,针对上述子控件进行样式设置
哪些样式有哪些子控件,可通过下面的方式搜索:
Qt Assistant -> Qt Style Sheet Reference -> List of Sub-Controls
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style = "#comboBox::down-arrow{image : url(:/down)}";ui->comboBox->setStyleSheet(style);
}
利用ID选择器和子控件选择器,对objectName
为comboBox
的下拉按钮设置图标
效果:
伪类选择器
并非选择一个控件,而是选择一个控件的状态
- 当状态具备时,控件被选中,样式生效
- 当状态不具备时,空间不被选中,样式不生效
伪类选择器 | 说明 |
---|---|
:hover | 鼠标放到控件上 |
:pressed | 鼠标左键按下时 |
:focus | 获取输入焦点时 |
:enabled | 元素处于可用状态时 |
:checked | 被勾选时 |
:read-only | 元素为只读状态时 |
注:可以通过 !
,的方式,对状态取反
可以通过:Qt Assistant -> Qt Style Sheet Reference -> List of Pseudo-States。进行更详细的查看
例如:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QString style ="#pushButton:hover {background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 ""rgb(255, 100, 100), ""stop: 1 ""rgb(100, 255, 100));}";ui->pushButton->setStyleSheet(style);
}
利用伪类选择器,当**光标进入****pushButton
**时,其背景颜色就会发生改变
效果:
渐变色
上面我们给pushButton
设置背景颜色时,用到了渐变色。下面来介绍渐变色的设置方法
线性渐变
所谓线性渐变,就是沿着从左往右、从上往下、对角线的方向进行颜色渐变
可以对左上、右上、左下、右下分别标点为 (0, 0), (0, 1), (1, 0), (1, 1)
用到的方法为:qlineargradient
例如:
QPushButton {background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 red, stop: 1 yellow);
}
x1
,y1
,即渐变起点的位置x2
,y2
,即渐变终点的位置stop
:渐变 stops 点,stop:0
对应起始颜色,stop:1
对应结束颜色,也可插入多个 stops 实现多色渐变,比如stop:0 red, stop:0.5 green, stop:1 blue
径向渐变
即从中心向外围扩散的渐变方式
用到的方法为:qradialgradient
例如:
QPushButton {/* 圆心在控件中心(0.5, 0.5),半径 0.5(控件尺寸一半),颜色从中心白色渐变到边缘黑色 */background: qradialgradient(cx: 0.5, cy: 0.5, radius: 0.5, stop: 0 white, stop: 1 black);
}
cx, cy
:渐变圆心坐标(0~1 范围,相对控件自身),(0.5, 0.5)
即控件中心。radius
:渐变半径(0~1 范围,相对于控件尺寸),0.5
表示以控件一半大小为半径。stop
:同线性渐变,控制颜色分布。
例如:
#dial::chunk {background : qradialgradient(cx: 0.5, cy: 0.5, radius: 0.5, stop: 0 green, stop: 1 blue);
}
盒子模型 Box Model
Qt中,每个Widget
都是一个矩形,那么这个矩形,从里到外都可以分为四个部分:
-
CONTENT
:内容 -
PADDING
:内边距。内容区与边框(BORDER)之间的空白区域,用于控制内容与边框的间距,会影响元素整体占位大小(padding 会让元素 “变大” ),且背景色会覆盖内边距区域。 -
BORDER
:边距。包裹内容和内边距的线条,可设置样式border-style
(如实线、虚线)、宽度border-width
、颜色border-color
,是元素视觉边界 -
MARGIN
:外边距。最外层,用于控制当前元素与其他元素之间的空白间距,不影响元素自身大小,但会影响与相邻元素的布局关系(如上下元素的间距由margin-top
/margin-bottom
决定 ),且 外边距区域无背景色。 其可拆分为四个属性margin-left
margin-right
margin-top
margin-bottom
- 使用时,可以写为
margin : 10px
,即上下左右分别10px - 也可以写为
margin: 10px, 20px
,即上下10px,左右20px - 也可以写为
margin: 10px, 20px, 30px, 40px
,以上右下左的顺序(顺时针)进行设置 padding
属性同理
-
默认情况下
margin
、padding
、border-width
为0
例如:
Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("这是一个按钮");button->setGeometry(0, 0, 300, 300);button->setObjectName("button");QString style ="#button {""border : 20px solid rgb(200, 100, 100);""padding : 50px;""margin : 30px;""text-align: left;" // 改为左对齐"}";button->setStyleSheet(style);
}
效果:
样例
修改复选框样式
#checkBox {font-size : 20px;color : blue;
}#checkBox::indicator:unchecked {image : url(:/source/white-no.png);
}#checkBox:indicator:unchecked:hover {image : url(:/source/blue-no.png);
}#checkBox:indicator:unchecked:pressed {image : url(:/source/red-yes.png);
}#checkBox:indicator:checked {image : url(:/source/white-yes.png);
}#checkBox:indicator:checked:hover {image : url(:/source/blue-yes.png);
}#checkBox:indicator:checked:pressed {image : url(:/source/red-yes.png);
}
效果:
修改单行编辑框样式
#lineEdit {border-radius: 10px;border : 3px solid rgb(110, 110, 110);padding : 5px;font-size: 15px;background-color: rgb(197, 197, 197);color : rgba(1, 40, 49, 0.523);selection-background-color: rgb(116, 1, 1); // 修改被选中文本的背景色selection-color: rgb(148, 243, 152); // 修改被选中文本的文本色
}
效果:
实现一个简单的登陆界面
实现一个简单的登录页,包含以下功能:
- 设置背景图片
- 设置各个控件的样式
- 可以控制用户密码的显示与隐藏
- 可以根据窗口大小的变化,自动调节控件布局
注意:Qt不允许直接给主窗口QWidget
设置背景图片,只能通过向主窗口添加一个QFrame
控件,对这个frame
进行背景图设置
QFrame 基本功能
- 提供边框样式:
QFrame
可以设置多种边框样式,如Box
(矩形框)、Panel
(面板样式)、Sunken
(凹陷样式)、Raised
(凸起样式) 等。通过设置边框样式,能让界面元素更具层次感和视觉吸引力。例如,在设计登录界面时,可以使用QFrame
作为输入框区域的容器,并设置为凹陷样式,使其看起来像是一个独立的输入面板。- 背景和填充:除了边框,
QFrame
还可以设置背景颜色或背景图片,从而进一步定制其外观。这对于创建具有特定风格的界面组件非常有用,比如为一个包含多个按钮的区域添加一个带有颜色或图案的背景。
Qt Desginer
展示:
代码:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QResizeEvent>
#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void resizeEvent(QResizeEvent *event);private slots:void on_toolButton_clicked();private:Ui::Widget *ui;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"#include <QLineEdit>
#include <QPushButton>#include "./ui_widget.h"Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ui->label->setAlignment(Qt::AlignCenter);// 设置背景图QString style_frame ="#frame {""border-image : url(:/background);""}";ui->frame->setStyleSheet(style_frame);// 设置输入框样式QString style_edit =".QLineEdit {""background-color : rgba(50, 50, 50, 0.7);""border : 1px solid rgb(160, 100, 200);""border-radius : 10px;""font-size : 15px;""padding : 5px;""}";ui->lineEdit->setStyleSheet(style_edit);ui->lineEdit_2->setStyleSheet(style_edit);ui->lineEdit->setEchoMode(QLineEdit::Normal);ui->lineEdit_2->setEchoMode(QLineEdit::Password);ui->lineEdit->setClearButtonEnabled(true);ui->lineEdit_2->setClearButtonEnabled(true);ui->lineEdit->setPlaceholderText("请输入用户uid");ui->lineEdit_2->setPlaceholderText("请输入密码");// 设置 ToolButton样式QString style_tool ="QToolButton {"" background-color: white !important;"" padding: 5px;""}";ui->toolButton->setStyleSheet(style_tool);ui->toolButton->setCheckable(true);ui->toolButton->setChecked(false);ui->toolButton->setIcon(QIcon(":/closeEyes"));// 设置pushButton样式QString style_push ="#pushButton {"" background: rgba(0, 0, 0, 0.6); "" border-radius: 10px; "" border: 1px solid rgba(255, 255, 255, 0.5); "" color: white; "" padding: 8px 20px; ""}""#pushButton:hover {"" background: rgba(255, 255, 255, 0.3); ""}""#pushButton:pressed {"" padding: 7px 3px 3px 7px;"" border: 1px solid darkgray;""}";ui->pushButton->setStyleSheet(style_push);
}Widget::~Widget() { delete ui; }void Widget::resizeEvent(QResizeEvent* event) {ui->frame->setGeometry(0, 0, event->size().width(), event->size().height());
}// 控制密码显示
void Widget::on_toolButton_clicked() {if (ui->toolButton->isCheckable() == false) {ui->toolButton->setIcon(QIcon(":/openEyes"));ui->toolButton->setCheckable(true);ui->lineEdit_2->setEchoMode(QLineEdit::Normal);} else {ui->toolButton->setIcon(QIcon(":/closeEyes"));ui->toolButton->setCheckable(false);ui->lineEdit_2->setEchoMode(QLineEdit::Password);}
}
绘图
有时候Qt已有的控件无法满足我们的需求,为了应对这种情况,就需要用到绘图,自己实现满足要求的控件
核心类:
类 | 说明 |
---|---|
QPainter | “绘画者” 或者 “画家”。 用来绘图的对象,提供了一系列 drawXXX 方法,可以允许我们绘制各种图形。 |
QPaintDevice | “画板”。 描述了 QPainter 把图形画到哪个对象上。像咱们之前用过的 QWidget 也是一种 QPaintDevice(QWidget 是 QPaintDevice 的子类)。 |
QPen | “画笔”。 描述了 QPainter 画出来的线是什么样的。 |
QBrush | “画刷”。 描述了 QPainter 填充一个区域是什么样的。 |
画图的相关操作,一般不放到狗杂函数中进行。
Qt提供了一个**paintEvent
**事件处理函数,在这里进行绘图调用。当QpaintEvent
事件触发的时候,事件函数就会执行
- 控件首次创建的时候
- 空间被遮挡,然后被解除遮挡的时候
- 窗口被最小化,然后被还原的时候
- 控件大小发生改变的时候
- 主动在代码中调用
repaint
或者update
的时候
绘制形状
线段
void QPainter::drawLine(int x1, int y1, int x2, int y2)
void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
指定起点和终点的横纵坐标,绘制线段
矩形
void QPainter::drawRect(int x, int y, int width, int height)
指定左上角坐标,指定长宽
圆
void QPainter::drawEllipse(int x, int y, int width, int height)
指定圆心横纵坐标,并确定外接矩形的高和宽
文字
void QPainter::drawText(int x, int y, const QString &text)
void QPainter::drawText(const QPoint &position, const QString &text)
x
:是文字的最左侧位置y
:是文字的基线位置。四线格的第三根线
例如:
#include "widget.h"#include <QBrush>
#include <QPainter>
#include <QPen>#include "./ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); }Widget::~Widget() { delete ui; }void Widget::paintEvent(QPaintEvent *evnet) {QPainter painter(this);QPen pen;pen.setColor("red"); // 设置画笔颜色pen.setWidth(2); // 设置画笔宽度pen.setStyle(Qt::PenStyle::DashLine); // 设置画笔类型painter.setPen(pen); // 讲画笔设置给画家painter.drawLine(10, 10, 88, 88); // 画线段painter.setFont(QFont("微软雅黑", 20)); // 设置画家字体painter.drawText(300, 50, "HELLO WORD"); // 写字// 设置径向渐变画刷QLinearGradient gradient(100, 100, 500, 500);gradient.setColorAt(0, Qt::red);gradient.setColorAt(1, Qt::blue);QBrush brush(gradient); // 直接用渐变初始化画刷(无需额外设置样式)painter.setBrush(brush); // 讲画刷设置给画家painter.drawEllipse(100, 100, 300, 300); // 以 (100, 100)半径500px画圆// 设置brush.setColor("white");brush.setStyle(Qt::HorPattern);painter.setBrush(brush); // 讲画刷设置给画家// 画矩形painter.drawRect(400, 350, 200, 200);
}
效果:
图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture,它们都是常用的绘图设备。
-
QImage
主要用来进行 I/O 处理,它对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素; -
QPixmap
主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化; -
QBitmap
是 QPixmap 的子类,用来处理颜色深度为 1 的图像,即只能显示黑白两种颜色; -
QPicture
用来记录并重演 QPainter 命令
这里主要介绍QPixmap
void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap)
void QPainter::drawPixmap(int x, int y, int width, int height, const QPixmap &pixmap)
- 从
x
,y
开始,绘制图片 - 并将图片绘制成大小
width * height
例如:
#include "widget.h"#include <QBrush>
#include <QPixmap>#include "./ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); }Widget::~Widget() { delete ui; }void Widget::paintEvent(QPaintEvent *evnet) {QPainter painter(this);QPixmap map(":/photo");painter.drawPixmap(20, 20, 800, 600, map);
}
效果:
如果想要旋转图像,以旋转180度为例,操作步骤如下:
-
保存当前坐标系状态
painter.save();
-
旋转坐标轴(旋转画家)
painter.rotate(180);
-
移动坐标原点(将坐标原点从左上角移动到右下角)
painter.translate(-this->geometry().width(), -this->geometry().height());
-
绘制图像
painter.drawPixmap(20, 20, 800, 600, map);
-
恢复坐标系状态
painter.restore();