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

Qt:Qt界面优化

目录

QSS

QSS背景介绍

QSS基本语法

QSS设置方法

指定控件样式设置

全局样式设置

从文件加载样式表

使用Qt Designer编辑样式

选择器

选择器概况

子控件选择器

伪类选择器

样式属性(盒模型)

控件样式

按钮

复选框

绘图

基础概念

绘制各种形状

设置画笔

设置画刷

绘制图片

其他设置

移动画家设置

保存/加载画家的状态

特殊的绘图设备

QPixmap

QImage

QPicture


QSS

QSS背景介绍

在网页前端开发领域中,CSS是⼀个至关重要的部分,描述了⼀个网页的"样式",从起到对网页美化的作用。

  • 所谓样式,包括不限于大小,位置,颜色,背景,间距,字体等等。
  • 现在的网页很难找到没有CSS的,可以说让"界面好看"是⼀个刚需。
  • 网页开发作为GUI的典型代表,也对于其他客户端GUI开发产⽣了影响.Qt也是其中之⼀.

Qt 仿照CSS的模式,引入了QSS,来对Qt中的控件做出样式上的设定,从而允许程序员写出界面更好看的代码。

  • 同样受到HTML的影响,Qt还引⼊了QML来描述界面,甚至还可以直接把⼀个原生的html页面加载到界面上,这部分内容这里不做讨论。

当然,由于Qt本身的设计理念和网页前端还是存在一定差异的,因此QSS中只能支持部分CSS属性,整体来说QSS要比CSS更简单⼀些。

注意:如果通过QSS设置的样式和通过C++代码设置的样式冲突,则QSS优先级更高。


QSS基本语法

对于CSS来说,基本的语法结构非常简单

选择器
{
    属性名: 属性值; 
}

QSS沿用户了这样的设定

选择器
{
    属性名: 属性值; 
}

其中:

  • 选择器:描述了"哪个widget要应用样式规则"
  • 属性:是一个键值对,属性名表示要设置哪种样式,属性值表示了设置的样式的值

例如:

QPushButton { color: red; }

或者:

QPushButton {
    color: red;
}

QSS设置方法

指定控件样式设置

QWidget 中包含了 setStyleSheet 方法,可以直接设置样式。给指定控件设置样式之后,该控件的子元素也会受到影响

代码示例:子控件受影响

在界面上创建一个按钮

修改widget.cpp,不给按钮设置样式,而是给 Widget 设置样式(Widget是QPushButton的父控件)

#include "widget.h"
#include "ui_widget.h"
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setStyleSheet("QPushButton { color:red }");
}
 
Widget::~Widget()
{
    delete ui;
}

运行程序,可以看到样式对于子控件按钮同样会生效

全局样式设置

可以通过 QApplication 的 setStyleSheet 方法设置整个程序的全局样式

全局样式优点:

  • 使同一个样式针对多个控件生效,代码更简洁
  • 所有控件样式内聚在一起,便于维护和问题排查

代码示例:使用全局样式

在界面上创建三个按钮

编辑main.cpp,设置全局样式

#include "widget.h"
 
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyleSheet("QPushButton { color:red; }");
 
    Widget w;
    w.show();
    return a.exec();
}

此时三个按钮的颜色都设置为红色了

代码示例:样式的层叠性

若通过全局样式给某个控件设置了属性1,通过指定控件样式给控件设置属性2,那么这两个属性都会产生作用

在界面上创建两个按钮

编写main.cpp,设置全局样式,把按钮文本设置为红色。

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

    // 设置全局样式
    a.setStyleSheet("QPushButton { color: red; }");

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

编写widget.cpp,给第⼀个按钮设置字体大小

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置指定控件样式
    ui->pushButton->setStyleSheet("QPushButton { font-size: 50px} ");
}

运行程序,可以看到,对于第⼀个按钮来说,同时具备了颜色和字体大小样式,而第⼆个按钮只有颜色样式,说明针对第⼀个按钮,两种设置方式设置的样式,叠加起来了。

形如上述这种属性叠加的效果,我们称为"层叠性",CSS全称为CascadingStyleSheets,其中Cascading就是"层叠性"的意思,QSS也继承了这样的设定,实际上把QSS叫做QCSS也许更合适⼀些。

代码示例:样式的优先级

如果果全局样式,和指定控件样式冲突,则指定控件样式优先展示,在界面上创建两个按钮

编辑main.cpp,把全局样式设置为红色

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

    // 设置全局样式
    a.setStyleSheet("QPushButton { color: red; }");

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

编辑widget.cpp,把第⼀个按钮样式设为绿色

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置第⼀个按钮颜⾊为绿⾊
    ui->pushButton->setStyleSheet("QPushButton { color: green; }");
}

运行程序,观察效果,可以看到第⼀个按钮已经成为绿色了,但是第⼆个按钮仍然是红色。

在CSS中也存在类似的优先级规则,通常而言都是"局部"优先级高于"全局"优先级,相当于全局样式先"奠定基调",再通过指定控件样式来"特事特办"。

从文件加载样式表

上述代码都是把样式通过硬编码的方式设置的,这样使QSS代码和C++代码耦合在一起了,并不方便代码的维护。因此更好的做法是把样式放到单独的文件中,然后通过读取文件的方式来加载样式

代码示例:从文件加载全局样式

在界面上创建一个按钮

创建 resource.qrc 文集,并设定前缀为 /

创建 style.qss 文件,并添加到 resource.qrc 中

style.qss 是需要程序运行时加载的,为了规避绝对路径的问题,仍然使用 qrc 的方式来组织(即把资源文件内容打包到cpp代码中)。Qt Creator没有提供创建 qss 文件的选项,直接右键->新建文件->手动设置文件扩展名为qss即可。

使用Qt Creator打开 style.qss 编写内容

QPushButton {
    color: red;
}

修改main.cpp,新增一个函数加载样式,并在main函数中调用上述函数设置样式

#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);
 
    QString style = loadQSS();
    a.setStyleSheet(style);
 
    Widget w;
    w.show();
    return a.exec();
}

使用Qt Designer编辑样式

QSS也可以通过Qt Designer直接编辑,实时预览,同时也能免C++和QSS代码的耦合

代码示例:使用Qt Designer编辑样式

右键按钮,选择"改变样式表"

在弹出的样式表编辑器中,可以直接填写样式。填写完毕点击OK即可

此时Qt Designer的预览界面就会实时显示出样式的变化

这种方式设置样式,样式内容会被以xml格式记录到ui文件中

<property name="styleSheet">
<string notr="true">QPushButton { color: red; }</string>
</property>

同时在控件的 styleSheet 属性中也会体现


选择器

选择器概况

选择器示例说明
全局选择器*选择所有的widget
类型选择器(type selector)QPushButton选择所有的QPushButton和其子类的控件
类选择器.QPushButton选择所有的QPushButton,不会选择子类
ID选择器#pushButton_2选择objectName为pushButton_2的控件
后代选择器QDialog QPushButton选择QDialog的所有后代中的QPushButton(子控件、孙子控件等)
子选择器QDialog>QPushButton选择QDialog的所有子控件中的QPushButton
并集选择器QPushButton,QLineEdit选择QPushButton、QLineEdit这两种控件
属性选择器QPushButton[flat="false"]选择所有QPushButton中,flat属性为false的控件

总体来说,QSS选择器的规则和CSS选择器基本⼀致

代码示例:使用类型选择器选中子类控件

在界面上创建⼀个按钮

修改main.cpp,设置全局样式

注意,此处选择器使用的是QWidget,QPushButton也是QWidget的子类,所以会受到QWidget选择器的影响。

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

    // 设置全局样式
    a.setStyleSheet("QWidget { color: red; }");

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

运行程序,可以看到按钮的文本颜色已经是红色了

如果把上述样式代码修改为下列代码

a.setStyleSheet(".QWidget { color: red; }");

此时按钮的颜色不会发生改变,此时只是选择QWidget类,而不会选择QWidget的子类QPushButton了。

代码示例:使用id选择器

在界面上创建3个按钮,objectName为pushButton,pushButton_2,pushButton_3

编写main.cpp,设置全局样式

  • 先通过QPushButton设置所有的按钮为黄色
  • 再通过#pushButton和#pushButton_2分别设置这两个按钮为红色和绿色
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 设置全局样式
    QString style = "";
    style += "QPushButton { color: yellow; }";
    style += "#pushButton { color: red; }";
    style += "#pushButton_2 { color: green; }";
    a.setStyleSheet(style);

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

执行程序,观察效果

当某个控件,通过 类型选择器 和 ID选择器 设置了冲突的样式时,ID选择器样式优先级更高。同理,若是其他的多种选择器作用同一个控件时出现冲突的样式,也会涉及到优先级问题。Qt文档上有具体的优先级规则介绍(参见The Style Sheet Syntax的Conflict Resolution章节)。

实践中可以简单的认为,选择器描述的范围越精准,则优先级越高。⼀般来说,ID选择器优先级是最高的。

子控件选择器

有些控件内部包含了多个"子控件",如QComboBox的下拉后的面板,如QSpinBox的上下按钮等。可以通过子控件选择器::,针对上述子控件进行样式设置

注意:哪些控件拥有哪些子控件,参考文档Qt Style Sheets Reference中List of Sub-Controls章节

代码示例:设置下拉框的下拉按钮样式。

在界面上创建一个下拉框并创建几个选项

创建 resource.qrc 并导入图片 down.png

使用子控件选择器 QComboBox::down-arrow 选中 QComboBox 的下拉按钮,再通过 image 属性设置图片。

#include "widget.h"
 
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    QString style = "QComboBox::down-arrow { image:url(:/down.png); }";
    a.setStyleSheet(style);
 
    Widget w;
    w.show();
    return a.exec();
}

执行程序,观察效果

伪类选择器

伪类选择器是根据控件所处的某个状态被选择的。如按钮被按下、输入框获取到焦点、鼠标移动到某个控件上等

  • 当状态具备时,控件被选中,样式生效
  • 当状态不具备时,控件不被选中,样式失效
  • 使用:的方式定义伪类选择器

常用的伪类选择器:

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

这些状态可以使用 ! 来取反,如 :!hover 就是鼠标离开控件时,:!pressed 就是鼠标松开时,等等

更多伪类选择器的详细情况,参考Qt Style Sheets Reference 的 Pseudo-States 章节。

代码示例:设置按钮的伪类样式

在界面上创建⼀个按钮

编写main.cpp,创建全局样式

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();
}

运行程序,可以看到,默认情况下按钮文字是红色,鼠标移动上去是绿色,鼠标按下按钮是蓝色。


样式属性(盒模型)

文档的 Qt Style Sheets Reference 章节详细介绍了哪些控件可以设置属性,每个控件都能设置哪些属性等。

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

  • Content矩形区域:存放控件内容,如包含的文本/图标等
  • Border矩形区域:控件的边框
  • Padding矩形区域:内边距,边框和内容之间的距离
  • Margin矩形区域:外边距,边框到控件 geometry 返回的矩形边界的距离

默认情况下,外边距、内边距、边框宽度都是0,可以通过一些QSS属性来设置上述的边距和边框的样式。

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

代码示例:设置边框和内边距

在界面上创建⼀个label

修改main.cpp,设置全局样式

  • border: 5px solid red 相当于border-style: solid; border-width: 5px; border-color: red; 三个属性的简写形式
  • padding-left: 10px; 是给左侧设置内边距
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    a.setStyleSheet("QLabel { border: 5px solid red; padding-left: 10px; }");

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

运行程序,可以看到样式发生了变化


控件样式

按钮

代码示例:自定义按钮

界面上创建⼀个按钮

右键->改变样式表,使用QtDesigner设置样式

QPushButton {
     font-size: 20px;
     border: 2px solid #8f8f91;
     border-radius: 15px;
     background-color: #dadbde;
}
QPushButton:pressed {
     background-color: #f6f7fa;
}

执行程序,可以看到效果

属性小结

属性说明
font-size设置文字大小
border-radius设置圆角矩形.
数值设置的越大,角就"越圆"
background-color设置背景颜色

形如 #dadbde 是计算机中通过十六进制表示颜色的方式,这里在"常用控件"章节已经介绍过了,此处不再赘述。

另外,在实际开发中,颜色具体使用哪种好看,是需要⼀定的"艺术细菌"的,往往会有更专业的美工/设计人员来负责,程序员只需要按照设计稿实现程序即可。

复选框

代码示例:自定义复选框

创建⼀个 resource.qrc 文件,并导入以下图片

使用黑色作为默认形态,使用黑色作为hover形态,使用红色作为pressed形态

创建⼀个复选框

编辑复选框的样式

QCheckBox {
     font-size: 20px;
}
QCheckBox::indicator {
     width: 20px;
     height: 20px;
}
QCheckBox::indicator:unchecked {
     image: url(:/checkbox-unchecked.png);
}
QCheckBox::indicator:unchecked:hover {
     image: url(:/checkbox-unchecked_hover.png);
}
QCheckBox::indicator:unchecked:pressed {
     image: url(:/checkbox-unchecked_pressed.png);
}
QCheckBox::indicator:checked {
     image: url(:/checkbox-checked.png);
}
QCheckBox::indicator:checked:hover {
     image: url(:/checkbox-checked_hover.png);
}
QCheckBox::indicator:checked:pressed {
     image: url(:/checkbox-checked_pressed.png);
}

运行程序,可以看到此时的复选框就变的丰富起来了

除了上述之外,还有包括像单选框、列表、输入框等各种控件,在这里就不一一演示了。

QSS本身给Qt提供了更丰富的样式设置的能力,但是整体来说QSS的功能是不如CSS的。

在CSS中,整个网页的样式,都是CSS一手负责,CSS功能更强大,并且也更可控。

相⽐之下,Qt中是以原生api为主,来控制控件之间的尺寸、位置等,QSS只是起到辅助的作用。

而且Qt中提供的⼀些"组合控件"(像QComboBox,QSpinBox等)内部的结构是不透明的,此时进行一些样式设置也会存在⼀定的局限性。

另外,做出好看的界面,光靠QSS是不够的,更重要的是需要专业美工做出设计稿,这里主要是了解这个技术。


绘图

基础概念

Qt提供了画图相关的API,可以允许在窗口上绘制任意的图形形状,来完成更复杂的界面设计

注意:所谓的"控件",本质上也是通过画图的方式画上去的。画图 API 和 控件 之间的关系,可以类比成机器指令和高级语言之间的关系。控件是对画图 API 的进一步封装,画图 API 是控件的底层实现。

绘图API核心类

说明
QPainter"绘画者"或者"画家"
用来绘图的对象,提供了⼀系列drawXXX方法,可以允许我们绘制各种图形
QPaintDevice"画板"
描述了QPainter把图形画到哪个对象上,像咱们之前⽤过的QWidget也是⼀种QPaintDevice(QWidget是QPaintDevice的子类)
QPen"画笔"
描述了QPainter画出来的线是什么样的
QBrush"画刷"
描述了QPainter填充⼀个区域是什么样的

绘图 API 的使用,一般不会在 QWidget 的构造函数中使用,而是要放到 paintEvent 事件中

paintEvent 事件会在以下情况下被触发:

  • 控件首次创建
  • 控件被遮挡,再解除遮挡
  • 窗口最小化,再恢复
  • 控件大小发生变化时
  • 主动调用 repaint() 或者 update() 方法(这两个方法都是 QWidget 的方法)
  • ......

绘制各种形状

绘制线段

void drawLine(const QPoint &p1, const QPoint &p2);
//p1:绘制起点坐标
//p2:绘制终点坐标
 
void drawLine (int x1, int y1, int x2, int y2);
//x1,y1:绘制起点坐标
//x2,y2:绘制终点坐标

绘制矩形

void QPainter::drawRect(int x, int y, int width, int height);
//x:窗⼝横坐标
//y:窗⼝纵坐标
//width:所绘制矩形的宽度
//height:所绘制矩形的⾼度

绘制圆形

void QPainter::drawEllipse(const QPoint &center, int rx, int ry)
//center:中⼼点坐标
//rx:外接矩形横坐标
//ry:外接矩形纵坐标

绘制文本


设置画笔

QPainter在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在Qt中,QPen类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen类 可以设置画笔的线宽、颜色、样式等

  • 设置画笔颜色:QPen::QPen(const QColor &color) 画笔的颜色主要是通过 QColor 类设置
  • 设置画笔宽度:void QPen::setWidth(int width)
  • 设置画笔风格:void QPen::setStyle(Qt::PenStyle style)


设置画刷

在 Qt 中,画刷是使用 QBrush类 来描述,画刷大多用于填充。QBrush定义了QPainter的填充模式,具有样式、颜色、渐变以及纹理等属性

画刷的格式中定义了填充的样式,使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush,也就是不进行任何填充。可以通过 Qt 助手 查找画刷的格式

设置画刷主要通过void QPen::setBrush(const QBrush &brush)方法,其参数为画刷的格式


绘制图片

Qt提供了四个类来处理图像数据:QImage、QPixmap、QBitmap和QPicture,都是常用的绘图设备。其中 QImage 主要用来进行 I/O 处理,对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素;QPixmap主要用来在屏幕上显示图像,对在屏幕上显示图像进行了优化;QBitmap是QPixmap的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;QPicture用来记录并重演 QPainter 命令。

绘制简单图片

平移图片

平移图片实际是通过改变坐标来实现。QPainter类提供了 translate()函数 来实现坐标原点的改变

缩放图片

在 Qt 中,图片的放大和缩小可以使用 QPainter类 中的drawPixmap()函数来实现

旋转图片

图片的旋转使用的是 QPainter类 中的 rotate()函数,默认是以原点为中心进行旋转的。若要改变旋转的中心,可以使用translate()函数完成。


其他设置

移动画家设置

有时候在绘制多个图形时,使用同⼀坐标位置,那么绘制出来的图形肯定会重合。可以通过移动画家的位置来使图形不发生重合。

保存/加载画家的状态

在绘制图形的过程中,可以通过 save() 函数来保存画家的状态,使用 restore() 函数还原画家状态

save()函数原型如下:

restore()函数原型如下:

代码示例

上述示例中,在画第三个圆之前,由于还原了画家的状态,所以此时画家的位置坐标会移动到画家状态保存的地方,所以在绘制第三个圆的位置时实际是和第二个圆发生了重叠。


特殊的绘图设备

前⾯的代码中是使用 QWidget 作为绘图设备,在 Qt 中还存在下列三个特殊的绘图设备

  • QPixmap 用于在显示器上显示图片
  • QImage 用于对图片进行像素级修改
  • QPicture 用于对 QPainter 的一系列操作进行存档

QPixmap

QPixmap核心特性

  • 使用 QPainter 直接在上面进行绘制图形
  • 通过文件路径加载并显示图片
  • 搭配 QPainter 的 drawPixmap()函数,可以把这个图片绘制到QLabel、QPushButton等控件上
  • 和系统/显示设备强相关,不同系统/显示设备下,QPixmap 的显示可能会有所差别

QImage

QImage核心特性

  • 使用 QPainter 直接在上面进行绘制图形
  • 通过文件路径加载并显示图片
  • 能够针对图片进行像素级别的操作(操作某个指定的像素)
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示

QPicture

QPicture核心特性

  • 使用 QPainter 直接在上面进行绘制图形
  • 通过文件路径加载并显示图片
  • 能够记录 QPainter 的操作步骤
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示

注意:QPicture加载的必须是自身的存档文件,而不能是任意的png、jpg等图片文件

认识

QPicture类似于很多游戏的Replay功能。如war3经典游戏,即使是一场60分钟的长时间局,生成的replay文件,也不过几百个KB

此处的Replay功能并非是把整个游戏画面都录制保存下来,而是记录了地图中发生的所有事件(地图元素,玩家单位操作,中立生物行为等...)

当回放Replay时,其实就是把上述记录的事件再一条一条的执行一遍,即可还原之前的游戏场景

代码示例

若要记录下 QPainter 的命令,先要使用 QPainter::begin() 函数,将 QPicture 实例作为参数传递进去,以便告诉系统开始记录,记录完毕后使用 QPainter::end() 命令终止。

相关文章:

  • 第6章 6.2使用ASP.NET Core 开发WebAPI ASP.NET Core Web API
  • 【网络安全 | 漏洞挖掘】价值3133美元的Google IDOR
  • Node.js开发属于自己的npm包(发布到npm官网)
  • 算法——结合实例了解广度优先搜索(BFS)搜索
  • 进阶数据结构——离散化
  • 5. Docker 本地镜像发布到阿里云
  • 巨控GRM530无线远程模块与工业物联网融合技术方案
  • python爬虫解决无限debugger问题
  • Datawhale 组队学习 wow-agent task1 学习总结
  • CSS 属性选择器详解与实战示例
  • javaEE初阶————多线程初阶(4)
  • DeepSeek解决服务器繁忙,使用API接口进行使用
  • Git常用指令
  • wordpressAI工具,已接入Deepseek 支持自动生成文章、生成图片、生成长尾关键词、前端AI窗口互动、批量采集等
  • vue3实战-----封装和使用svg图标
  • 软考高级《系统架构设计师》知识点(一)
  • 自动从 Gitee 同步到 GitHub
  • MATLAB中iscategorical函数用法
  • Docker上安装Zabbix-server-mysql报错
  • 多能互补综合能源系统,改变能源结构---安科瑞 吴雅芳
  • 织梦做的网站能做seo吗/产品推广公司
  • 做网站公司的介绍/防恶意竞价点击软件
  • 知名网站欣赏/google seo怎么做
  • 自己怎么建个网站赚钱吗/网站alexa排名
  • 益阳网络公司/天津百度seo代理
  • 收费网站怎么做/b2b网站大全