QT跨平台应用程序开发框架(12)—— Qt界面样式优化

目录

[一,关于 QSS](#一,关于 QSS)

[1.1 关于 CSS](#1.1 关于 CSS)

[1.2 基本使用](#1.2 基本使用)

[1.3 两个问题](#1.3 两个问题)

[1.4 qss 文件](#1.4 qss 文件)

二,选择器

[2.1 基本用法](#2.1 基本用法)

[2.2 子控件选择器](#2.2 子控件选择器)

[2.3 伪类选择器](#2.3 伪类选择器)

三,盒模型

四,控件样式示例

[4.1 按钮](#4.1 按钮)

[4.2 复选框](#4.2 复选框)

[4.3 输入框](#4.3 输入框)

[4.4 列表框](#4.4 列表框)

[4.5 菜单](#4.5 菜单)

五,实现登录页面


前端开发 CSS 介绍:前端学习(2)------ CSS详解与使用_前端css-CSDN博客

一,关于 QSS

一个程序的界面是否好看也是非常重要的,所以界面优化也可以叫做界面"美化"

  • 面向专业领域的程序,不关心界面如何,更在意实际效果
  • 面向普通用户的程序,界面观感,是很大的加分项

1.1 关于 CSS

QSS 其实非常类似于网页前端开发的 CSS,可以参考:前端学习(2)------ CSS详解与使用_前端css-CSDN博客

它能够针对界面的"样式"来进行设置, 比如:大小,位置,颜色,背景等等

由于 QSS 是对 CSS 的模仿,所以在某些地方,QSS 比 CSS 要逊色一些,但是够用

1.2 基本使用

CSS 的语法结构非常简单,所以 QSS 沿用了这样的设定:

复制代码
选择器 {
    属性名: 属性值;
}
  • 选择器:描述了"哪个 widget 要设定样式"
  • 属性:是一个或多个键值对,属性名表示要设置哪种属性,属性值表示设置的样式的值

例如下面实例表示把所有按钮的文本颜色设置为 红色:

css 复制代码
QPushButton {
    color: red;
}

我们前面介绍 QWidget 常用属性时,已经介绍了 QSS 的两种设置方式:QT跨平台应用程序开发框架(4)------ 常用控件QWidget-CSDN博客

一种是直接代码设置,一种是在 ui 里设置

在代码设置就设置 setStyleSheet 属性即可:

css 复制代码
ui->pushButton->setStyleSheet("QPushButton { color: red; }");

一种是直接在 ui 界面添加,可以找到控件的 styleSheet 属性:

或者直接右键控件:

1.3 两个问题

问题一:如果设置了全局样式,然后又在某个空间里设置了其它的样式会怎样?

我们先创建三个按钮, 然后在 main.cpp 里设置全局样式,运行后按钮就会变为红色:

这时候,我们再去控件里再去设置样式,比如我们设置字体大小,结果变成了这样:

问题解答:可以看到,两方面的样式会"叠加"起来

问题二:如果设置了全局样式,再在某个空间里设置和全局样式冲突的样式如何?

比如我们全局样式设置红色,那我们就单独设置个 绿色,如下:

问题解答:可以看到,当冲突的时候,局部样式的优先级大于全局样式,可以说是先渲染了全局样式,后渲染的局部样式,导致局部样式覆盖了全局样式

1.4 qss 文件

  • 我们都知道,要把一个控件调成好看,肯定不止一条 QSS 语句,所以,如果我们像上面一样,C++ 的代码和 QSS 的代码混杂在一起,体量一大,代码维护成本直线飙升
  • 所以我们可以和前端开发一样,把 QSS 代码单独拿出来,放进一个 qss文件里,后续直接让 C++ 来读取加载文件内容,就可以完成 "基本代码" 和 "样式代码" 的"解耦",下面来演示一下

我们仍然用到 qrc 机制,这里不再赘述

创建好后,我们手动在电脑的文件管理器的项目目录下,新建一个 style.qss 文件,就和图片文件一样,只是图片变成了 .qss 文件,其余操作完全一致

在 qss 文件里设置和上面一样的改变按钮字体的样式后,就可以使用 C++ 代码来加载 qss 文件了,下面是 main.cpp 的内容:

cpp 复制代码
#include "widget.h"
#include <QApplication>
#include <QFile>

QString loadQSS()
{
    QFile file(":/style.qss");
    file.open(QFile::ReadOnly);
    QString style = file.readAll();
    file.close();
    return style;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //设置样式
    a.setStyleSheet(loadQSS());

    Widget w;
    w.show();
    return a.exec();
}

到了先在我们一共知道了三种设置样式的方法:C++ 代码添加、qss文件、ui界面添加

  • 但是最简单的还是直接在 ui 界面添加,只需要右键对应控件,点击"改变样式表"即可,它会直接添加进 ui 文件里,并且支持实时预览
  • 但是也由于设置样式太灵活,就导致某个控件样式不和预期时,排查起来比较麻烦

二,选择器

2.1 基本用法

选择器的含义可以参考:前端学习(2)------ CSS详解与使用_前端css-CSDN博客

这里不再赘述,下面是QSS 的部分支持的选择器,其中加粗的是比较重要的常用选择器:

选择器名称 示例 说明
全局选择器 * 选择所有的 widget
类型选择器(type selector) QPushButton 选择所有的 QPushButton 和 其子类的控件
类选择器 .QPushButton 选择所有 QPushButton 的控件,不过不会选择子类
ID 选择器 #pushButton_2 选择特定 objectName 的控件
后代选择器 QDialog QPushButton 选择 QDialog 的所有后代中的 QPushButton
子选择器 QDialog>QPushButton 选择 QDialog 的所有子空间中的 QPushButton
并集选择器 QPushButton, QLineEdit, QComboBox 选择指定的一种或多种控件,样式单独对这些控件生效,可和前面的嵌套使用
属性选择器 QPushButton[flat="false"] 选择所有 QPushButton 中,flat 属性为 false 的控件

①类型选择器

如果用 小点点 开头,那么就会变成类选择器,此时只会针对 QWidget 生效,不会对子类的 QPushButton 生效

②ID 选择器

单独针对一个控件进行的修改,如下:

注意:

  • 当某个控件,通过类型和 ID 选择器设置了冲突的样式,ID 选择器优先级更高
  • 同理,选择器也很多,也会涉及到优先级问题,Qt 文档上有具体的优先级规则介绍(可参考 The Style Sheet Syntax 的 Conflict Resolution 章节)
  • 当然,如何属性不冲突,那么也会相互叠加
    ③并集选择器

我们先创建三个不同的样式,然后可以使用并集选择器设置样式:

2.2 子控件选择器

部分控件内部包含了多个"子空间",比如 QComboBox 的下拉框的多个内容和 QSpinBox 微调框的上下选择按钮等,我们可以通过 子控件选择器"两个冒号",针对子空间进行样式设置

可以参考 Qt 文档 QtStyleSheetsReference 中 ListofSub-Controls 章节

下面简单演示一下,将下拉框的下拉按钮替换成别的图片:

2.3 伪类选择器

前面介绍的选择器都是选中控件,而伪类选择器选中的是控件的"状态",或者是选择"符合一定状态条件的控件",常用的伪类选择器如下:

伪类选择器 说明
:hover 鼠标放到控件上
:pressed 鼠标左键按下时
:focus 获取输入焦点时
:enabled 元素处于可用状态时
:checked 被勾选时
:read-only 元素为只读状态时

状态可以用 ! 来取反,比如 :!hover 激素鼠标离开控件时,:!pressed 就是鼠标松开时

更多内容可以参考 Qt 文档 QtStyleSheetsReference 的 Pseudo-States 章节

下面演示一下,比如我要让一个按钮在:"未按下"、"鼠标移动上去"、"鼠标按下"三种状态时,立马的文字分别显示不同颜色,如下代码:

cpp 复制代码
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    
    QString style = "";
    style += "QPushButton { color: red; }";
    style += "QPushButton:hover { color: green; }";
    style += "QPushButton:pressed { color: blue; }";
    a.setStyleSheet(style);

    Widget w;
    w.show();
    return a.exec();
}

上面的操作也可以通过事件来实现,但是比较麻烦,这里就不展示了,哪种方式便捷就选哪个

QSS 中样式非常多,不用特意去记忆,要用哪个就查哪个,而且大多数属性和 CSS 是一样的,文档的 Qt Style Sheet Reference 章节有详细介绍

三,盒模型

文档的 Customizing Qt Widgets Using Style Sheets 的 The Box Model 章节介绍了盒模型

关于盒模型我们的 CSS 文章里也有介绍,具体细节不再赘述:前端学习(2)------ CSS详解与使用_前端css-CSDN博客

可以通过一些 QSS 属性来设置上述的边距和边框的样式:

QSS 属性 说明
margin 设置四个方向的外边距,复合属性(left,right,top,bottom)
padding 设置四个方向的内边距,复合属性
border-style 设置边框样式
border-width 边框粗细
border-color 边框颜色
border 相当于 border-style + border-width + border-color

①示例一:设置边框和内边距

②示例二:设置外边距

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    QPushButton* btn = new QPushButton(this);
    btn->setGeometry(0, 0, 100, 100);
    btn->setText("hello");
    btn->setStyleSheet("QPushButton { border: 5px solid red; margin: 20px; }");
    
    const QRect& rect = btn->geometry();
    qDebug() << rect;
}

Widget::~Widget()
{
    delete ui;
}

虽然红色边框让按钮的白色区域看起来变小了,但是实际上控件的占用面积没有改变

四,控件样式示例

4.1 按钮

我们创建一个按钮,直接右键"改变样式表",使用 Qt Designer 设置样式:

css 复制代码
QPushButton {
    font-size: 20px;
    border: 2px solid #8f8f91; /*边框颜色*/
    border-radius: 15px; /*圆角矩形*/
    background-color: #dadbde; /*按钮背景颜色*/
 }
 QPushButton:pressed {
    background-color: #f6f7fa; /*按钮按下时的背景颜色*/
 }

4.2 复选框

先在 阿里巴巴矢量图标库下载类似下面的图片:

然后创建一个 Check Box,右键改变样式表:

css 复制代码
QCheckBox {
	font-size: 20px;
}

QCheckBox::indicator {
	width: 20px;
	height: 20px;
}

QCheckBox::indicator:unchecked {
	image: url(:/box/checkbox-unchecked.png);
}

QCheckBox::indicator:unchecked:hover {
	image: url(:/box/checkbox-unchecked_hover.png);
}

QCheckBox::indicator:unchecked:pressed {
	image: url(:/box/checkbox-unchecked_pressed.png);
}

QCheckBox::indicator:checked {
	image: url(:/box/checkbox-checked.png);
}

QCheckBox::indicator:checked:hover {
	image: url(:/box/checkbox-checked_hover.png);
}

QCheckBox::indicator:checked:pressed {
	image: url(:/box/checkbox-checked_pressed.png);
}
属性 说明
::indicator 子控件选择器 选中 checkbox 中的对钩部分
:hover 伪类选择器 鼠标移动上去的状态
:pressed 伪类选择器 鼠标按下的状态
:checked 伪类选择器 checkbox 被选中的状态
:unchecked 伪类选择器 checkbox 未被选中的状态
width 设置子控件宽度 对于普通控件无效(普通控件使用 geometry 方式设定尺寸)
height 设置子控件高度 对于普通控件无效(普通控件使用 geometry 方式设定尺寸)
image 设置子控件的图片 像 QSpinBox,QComboBox 等可以使用这个属性来设置子控件的图片

4.3 输入框

创建一个Line Edit 控件并输入样式:

css 复制代码
QLineEdit {
	border-width: 1px; 
	border-radius: 10px;
	border-color: rgb(58, 58, 58);
	border-style: inset;
	padding: 0 8px;
	color: rgb(255, 255, 255);
	background:rgb(100, 100, 100);
	selection-background-color: rgb(187, 187, 187);
	selection-color: rgb(60, 63, 65);
}
属性 说明
border-width 设置边框宽度
border-radius 设置圆角矩形
border-color 设置边框颜色
border-style 设置边框风格
padding 设置内边距
color 设置文字颜色
background 设置背景颜色
selection-background-color 设置选中文字的背景颜色
selection-color 设置选中文字的文本颜色

4.4 列表框

在界面上创建一个 List Widget控件,双击控件可以添加元素,添加元素后添加下列样式:

cpp 复制代码
QListView::item:hover {
	background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
	stop: 0 #FAFBFE, stop: 1 #DCDEF1);
}

QListView::item:selected {
	border: 1px solid #6a6ea9;
	background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
	stop: 0 #6a6ea9, stop: 1 #888dd9);
}
属性 说明
::item 选中控件的子控件
:hover 选中鼠标悬停的条目
:selected 选中某个被选中的条目
background 设置背景颜色
border 设置边框
qlineargradient 设置渐变色

关于:qlineargradient

这是设置渐变色的一个属性,有 6 个参数,比如上面的样例,x1 和 y1 表示起点,x2 和 y2 表示终点,就像平面直角坐标系的两个点一样,这两个点描述了一个方向:

  • x1:0, y1:0, x2:0, y2:1,就是垂直方向从上向下进行颜色渐变
  • x1:0, y1:0, x2:1, y2:0,就是水平方向从左向右进行颜色渐变
  • x1:0, y1:0, x2:1, y2:1,就是从左上往右下方向进行颜色渐变

而上面例子后面的 stop 的两个参数,表示颜色从 stop0 向 stop1 进行渐变

4.5 菜单

先创建一个继承 QMainWindow 的项目,添加部分菜单栏:

输入下列样式:

css 复制代码
QMenuBar {
	background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 lightgray, stop:1 darkgray);
	spacing: 3px; /*多个菜单之间的空隙*/
}

QMenuBar::item {
	padding: 1px 4px;
	background: transparent;
	border-radius: 10px;
}

QMenuBar::item:selected { 
 	background: #a8a8a8;
}

QMenuBar::item:pressed {
	background: #888888;
}

QMenu {
	background-color: white;
	margin: 0 2px; /*外边距*/
}

QMenu::item {
	padding: 2px 25px 2px 20px;
	border: 3px solid transparent; 
}

QMenu::item:selected {
	border-color: darkblue;
	background: rgba(100, 100, 100, 150);
}

QMenu::separator {
	height: 2px;
	background: lightblue;
	margin-left: 10px;
	margin-right: 5px;
}
属性 说明
QMenuBar::item 选中菜单栏的元素
QMenuBar::item:selected 选中菜单栏中被选中的元素
QMenuBar::item:pressed 选中菜单栏中鼠标点击的元素
QMenu::item 选中菜单中的元素(注意菜单和菜单栏的区别)
QMenu::item:selected 选中菜单中被选中的元素
QMenu::separator 选中菜单中的分割线

五,实现登录页面

先创建下列控件:

准备一张图片,使用 prc 机制设置背景,符合直觉的做法,就是直接给 QWidget 顶层窗口设置背景图,但是 Qt 中有某种不明限制,直接给顶层窗口设置背景会失效

那么我们可以在上面控件上再套一个和窗口一样大小的 QFrame 控件(是 QWidget 的一个子类),再给这个 QFrame 用图片填充即可:

给 QWidget 或者 QFrame 添加下列样式:

cpp 复制代码
QFrame {
	border-image: url(:/background.png);
	/*相较于 background-image,这个的背景会自动跟随控件大小变化,前者是固定大小*/
}

/*输入框样式*/
QLineEdit {
	color: #8d98a1; /*文本颜色*/
	background-color: #405361; 
	padding: 0 5px;
	font-size: 20px;
	border-style: none;
	border-radius: 10px;
}

/*设置 checkbox样式*/
QCheckBox {
	color: white;
	background-color: transparent;
}

/*设置按钮样式*/
QPushButton {
	font-size: 20px;
	color: white;
	background-color: #555;
	border-style: outset;
	border-radius: 10px;
}
QPushButton:pressed {
	color: black;
	background-color: #ced1db;
	border-style: inset;
}

里面各控件的功能我们前面都实现过,这里不再赘述