[QT5] 常用控件: QWidget是什么? 了解 控件常用公共属性, QT的qrc资源管理机制...
Table of Contents

QT中已经内置了许多的控件: 点击按钮、单选按钮、复选按钮、文本框、下拉框、状态栏…

一个完善的QT桌面程序, 是由许多的控件组成的

所以, 控件是非常重要的内容, 常用的控件需要逐一了解

了解QT内置控件 Link to 了解 QT 内置控件

在前面的文章中, 简单的使用过两个控件QPushButtonQLabel, 对应点击按钮和文本标签

除此之外, QT内置了种类非常丰富的控件(但是颜值并不高), 打开QT Creator->Designer(双击QT项目的.ui文件)就能看到QT内置的控件:

在了解各种控件类之前, 先了解一下QWidget

QWidgetQT中控件的通用属性类, 在QT Designer中查看:

QWidget ** Link to QWidget **

QWidget拥有很多属性, 可以直接在QT的文档中查看:

|huge

也可以在QT Designer中查看:

|huger

对于常用的公共属性, 可以一一进行介绍一下

enabled Link to enabled

此属性, 用于设置控件的可用状态

QT提供了相关的接口:

接口功能
bool isEnabled() const;获取控件当前enabled
void setEnabled(bool);设置控件可用状态

添加两个QPushButton, 并将enabled属性设置为falsetrue

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>

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

    QPushButton* btn1 = new QPushButton(this);
    btn1->setText("按钮1");
    btn1->move(200, 200);
    btn1->setEnabled(false);

    QPushButton* btn2 = new QPushButton(this);
    btn2->setText("按钮2");
    btn2->move(300, 300);
    btn2->setEnabled(true);
}

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

执行结果为:

|huge

可以看到, 按钮1为灰色, 处于不可选中状态; 按钮2, 则处于正常状态

控件的enabled属性是可以随时改变的:

widget.h:

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
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>

QT_BEGIN_NAMESPACE
namespace Ui {
    class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT

public:
    Widget(QWidget* parent = nullptr);
    ~Widget();

private slots:
    void btn1ClickedHandler();
    void btn2ClickedHandler();

private:
    Ui::Widget* ui;
    QPushButton* btn1;
    QPushButton* btn2;
};
#endif // WIDGET_H

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>
#include <QDebug>

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

    btn1 = new QPushButton(this);
    btn1->setText("按钮1");
    btn1->move(200, 200);
    btn1->setEnabled(false);

    btn2 = new QPushButton(this);
    btn2->setText("按钮2");
    btn2->move(300, 300);
    btn2->setEnabled(true);

    connect(btn1, &QPushButton::clicked, this, &Widget::btn1ClickedHandler);
    connect(btn2, &QPushButton::clicked, this, &Widget::btn2ClickedHandler);
}

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

void Widget::btn1ClickedHandler() {
    qDebug() << "按钮1被点击, 槽函数执行";
}

void Widget::btn2ClickedHandler() {
    bool btn1Enabled = btn1->isEnabled();
    if (btn1Enabled)
        btn1->setEnabled(false);
    else
        btn1->setEnabled(true);
}

这段代码的执行结果为:

geometry Link to geometry

此属性, 用于设置当前控件的位置和尺寸, 即 (x, y)(width, height)

QTgeometry提供了几个接口, 用于获取当前控件的位置和尺寸设置当前控件的位置和尺寸

接口功能
inline const QRect &QWidget::geometry() const;获取控件当前geometry属性
inline void setGeometry(int x, int y, int w, int h);通过4个int设置控件的geometry属性
void setGeometry(const QRect &);通过QRect设置控件的geometry属性

实际的使用:

widget.cc:

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
58
59
60
61
62
63
64
65
66
67
#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>
#include <QDebug>
#include <QRect>

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

    btn1 = new QPushButton(this);
    btn1->setText("按钮1");
    btn1->move(200, 200);
    btn1->setEnabled(false);

    btn2 = new QPushButton(this);
    btn2->setText("按钮2");
    btn2->move(300, 300);
    btn2->setEnabled(true);

    QRect btn1Geom = btn1->geometry();
    QRect btn2Geom = btn2->geometry();
    qDebug("按钮1 坐标: (%d, %d), 尺寸: (%d, %d)", btn1Geom.x(), btn1Geom.y(), btn1Geom.width(), btn1Geom.height());
    qDebug("按钮2 坐标: (%d, %d), 尺寸: (%d, %d)", btn2Geom.x(), btn2Geom.y(), btn2Geom.width(), btn2Geom.height());

    connect(btn1, &QPushButton::clicked, this, &Widget::btn1ClickedHandler);
    connect(btn2, &QPushButton::clicked, this, &Widget::btn2ClickedHandler);
}

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

void Widget::btn1ClickedHandler() {
    qDebug() << "按钮1被点击, 槽函数执行";
}

void Widget::btn2ClickedHandler() {
    QRect btn1Geom = btn1->geometry();
    qDebug("按钮1 坐标: (%d, %d), 尺寸: (%d, %d)", btn1Geom.x(), btn1Geom.y(), btn1Geom.width(), btn1Geom.height());

    bool btn1Enabled = btn1->isEnabled();
    if (btn1Enabled) {
        // 可用
        btn1->setEnabled(false);
        btn1Geom.setX(200);
        btn1Geom.setY(200);
        btn1Geom.setWidth(100);
        btn1Geom.setHeight(30);

        btn1->setGeometry(btn1Geom);
        qDebug("重新设置按钮1 坐标: (%d, %d), 尺寸: (%d, %d)", btn1Geom.x(), btn1Geom.y(), btn1Geom.width(), btn1Geom.height());
    }
    else {
        // 不可用
        btn1->setEnabled(true);
        btn1Geom.setX(500);
        btn1Geom.setY(500);
        btn1Geom.setWidth(200);
        btn1Geom.setHeight(30);

        btn1->setGeometry(btn1Geom);
        qDebug("重新设置按钮1 坐标: (%d, %d), 尺寸: (%d, %d)", btn1Geom.x(), btn1Geom.y(), btn1Geom.width(), btn1Geom.height());
    }
}

这段代码的执行结果为:

geometry()接口, 可以获取控件当前的坐标和尺寸, 返回值是一个QRect对象

QRect对象包含x y width height, 四个属性

QRect对象, 可以通过qDebug() << QRect直接打印坐标和尺寸信息

setGeometry()接口, 则可以设置控件的坐标和尺寸, 可以通过传入QRect对象, 也可以通过传入四个int

跳跃的按钮(小玩具程序) Link to 跳跃的按钮(小玩具程序)

先通过图形化创建QPushButton控件, 并创建clicked信号的槽

然后实现槽函数就可以了:

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
#include "widget.h"
#include "ui_widget.h"

#include <ctime>

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

    srand(time(nullptr));
}

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

void Widget::on_pushButton_clicked() {
    // 获取窗口的尺寸, 防止按钮跳跃出窗口
    int winWidth = this->geometry().width();
    int winHeight = this->geometry().height();

    int x = rand() % winWidth;
    int y = rand() % winHeight;
	// 防止按钮越界
    x > (winWidth - ui->pushButton->geometry().width()) ? (x = winWidth - ui->pushButton->geometry().width()) : x;
    y > (winHeight - ui->pushButton->geometry().height()) ? (y = winHeight - ui->pushButton->geometry().height()) : y;

    ui->pushButton->setGeometry(x, y, ui->pushButton->geometry().width(), ui->pushButton->geometry().height());
}

这样一个简单的小游戏就实现了:

|huger

不过, 上面是实现了对clicked信号的槽, 还有一个信号是pressed

clicked是被点击, 而pressed是被按压

clicked由两个动作完整组成: 按压 和 抬起, 而pressed则仅表示被按压:

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
#include "widget.h"
#include "ui_widget.h"

#include <ctime>

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

    srand(time(nullptr));
}

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

void Widget::on_pushButton_pressed() {
    // 获取窗口的尺寸, 防止按钮跳跃出窗口
    int winWidth = this->geometry().width();
    int winHeight = this->geometry().height();

    int x = rand() % winWidth;
    int y = rand() % winHeight;

    x > (winWidth - ui->pushButton->geometry().width()) ? (x = winWidth - ui->pushButton->geometry().width()) : x;
    y > (winHeight - ui->pushButton->geometry().height()) ? (y = winHeight - ui->pushButton->geometry().height()) : y;

    ui->pushButton->setGeometry(x, y, ui->pushButton->geometry().width(), ui->pushButton->geometry().height());
}

pressed信号实现槽, 可以实现鼠标左键不松的状态下, 光标移动到按钮上, 按钮就跳跃移动:

|huger

WindowFrame的影响 ** Link to WindowFrame 的影响 **

WindowFrame一般是由系统的桌面环境提供的, 它通常是窗口默认的标题栏、边框等元素

|huger

边框也算WindowFrame的一部分

之前的代码中, QPushButton控件move()geometry()setGeometry()接口, 设置或获取的都是控件相对于Widget本体的位置信息(左上角为(0, 0)):

|huger

窗口的WindowFrame元素是没有被计算在内的

不过QT也提供了针对WindowFrame的接口

对于一个窗口, QT提供了一些接口, 能够获取当前窗口的位置、尺寸信息:

接口功能
int x() const;获取窗口相对于桌面的横坐标, 包含WindowFrame计算
int y() const;获取窗口相对于桌面的纵坐标, 包含WindowFrame计算
QPoint pos() const;获取窗口相对于桌面的位置, 包含WindowFrame计算
返回的QPoint包含(x, y)相关信息
QSize frameSize() const;获取窗口的尺寸, 包含WindowFrame计算
返回的QSize包含(width, height)相关信息
QRect frameGeometry() const;获取窗口相对于桌面的位置及尺寸, 包含WindowFrame计算
int width() const;获取窗口内Widget本体的宽, 不包含WindowFrame计算
int height() const;获取窗口内Widget本体的高, 不包含WindowFrame计算
QSize size() const;获取窗口内Widget的尺寸, 不包含WindowFrame计算
QRect rect() const获取窗口内Widget本体的位置及尺寸, 不包含WindowFrame计算
const QRect geometry() const;获取窗口内Widget本体的位置及尺寸, 不包含WindowFrame计算
void setGeometry();设置Widget本体或控件的位置及尺寸, 不包含WindowFrame计算

使用这段代码可以查看计算WindowFrame的窗口信息:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

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

void Widget::on_pushButton_clicked() {
    qDebug() << "包含 WindowFrame 的窗口信息: " << this->frameGeometry();
    qDebug() << this->geometry();
}

要想获取包含了WindowFrame的窗口属性

不能在窗口构造阶段进行获取, 因为WindowFrame是由系统的桌面环境提供的

所以, 在窗口构造阶段, WindowFrame还没有被添加, 无法正确获取:

|wide

windowTitle Link to windowTitle

上面QT Designer中, 对于QPushButton属性的展示 并没有关于窗口的属性, 因为这部分属性对QPushButton没有什么用, 所以 QT Designer没有进行展示

点击Widget窗口就能够看到window...的相关属性:

|huger


此属性, 用于设置窗口标题, 且只有对独立的窗口设置才有效

QT提供了两个相关接口:

接口功能
QString windowTitle() const;获取窗口标题
void setWindowTitle(const QString &);设置窗口标题

可以直接在Widget的构造函数里使用, 获取结果:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget) {
    ui->setupUi(this);
        
    QString title = this->windowTitle();
    qDebug() << title;
        
    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;
}

windowTitle这个属性只对独立的窗口有效, 不过 其他控件设置并不会报错:

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    QString title = this->windowTitle();
    qDebug() << title;

    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;

    btn = new QPushButton(this); 	// btn 添加为成员变量
    btn->setText("这是一个按钮");
    connect(btn, &QPushButton::clicked, this, &Widget::btnClickedHandler);
}

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

void Widget::btnClickedHandler() {
    btn->setWindowTitle("给按钮设置标题??");
}

执行代码, 点击按钮

什么事都没有发生

从结果来看, 给非独立窗口设置windowTitle不会发生报错, 所以 当预期是设置窗口的标题没有报错, 却又没有实现时, 可以查看一下是不是设置错控件了

windowIcon Link to windowIcon

此属性, 用于设置窗口的图标, 且此属性同样对独立窗口有效

QT提供的接口:

接口功能
QIcon windowIcon() const;获取窗口当前图标属性
void setWindowIcon(const QIcon &icon);设置窗口图标属性

设置windowIcon属性, 需要借助一个类QIcon

QIcon这个类虽然拥有很多成员, 但在这是windowIcon时, 用法非常简单

只需要通过图标文件路径实例化出QIcon对象就可以:

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    QString title = this->windowTitle();
    qDebug() << title;

    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;

    QIcon winIcon("c:/Users/humid1ch/smile.png");
    this->setWindowIcon(winIcon);
}

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

|huge

QIcon的图标路径, 除了绝对路径之外, 也可以使用相对路径

这里的相对路径, 是相对可执行程序的执行路径

我的项目路径在: C:\Users\humid1ch\gitCode\codeRecords\QT

|huge

可执行程序的所在目录是build-xxxxxdebug/release目录下:

而, QT Creator运行可执行程序时所在目录, 会在build-xxxxx目录下

所以, 修改QIcon的图标路径为./smile.png, 并将图标放在build-xxxxx目录下

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    QString title = this->windowTitle();
    qDebug() << title;

    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;

    QIcon winIcon("./smile.png");
    this->setWindowIcon(winIcon);
}

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

编译运行, 同样可以实现窗口图标的设置:

|huge

但是, 无论是绝对路径或是相对路径, 实际上都不能保证程序能实际找到图片资源

所以, QT提供有另一个方式来管理程序的资源: qrc

qrc资源管理机制 ** Link to qrc 资源管理机制 **

什么是qrc?

QT中, .qrc是一种xml类型的文件, .qrc的内容通常是文件资源的路径

.qrc文件描述的文件资源, 在QT Creator编译代码时, 会以二进制的形式加载到可执行程序中, 以实现程序直接对文件资源的使用, 不需要在磁盘中在保存一份

即, qrc机制管理的文件, 不需要在磁盘中保存一份, 程序也不需要以资源在磁盘中的相对或绝对路径访问资源, 而是可以直接通过特殊的路径, 访问已经被加载到可执行程序中的文件资源


QT Creator创建.qrc文件很简单:

要清楚.qrc文件的所在路径, 因为需要被.qrc管理的文件, 要与.qrc文件处于同级目录或子目录下

创建好.qrc文件之后, 就可以通过QT Creator添加要管理的文件资源了:

首先要添加Prefix, 即 前缀, 前缀是什么, 在代码中访问资源的路径就需要添加什么, 一般为/

然后可以在已添加的Prefix下添加文件, 点击Add Files添加文件资源, 且文件要处与.qrc同级目录或子目录下:

|huge

此时, .qrc文件内容为:

|huger

然后, 就可以在代码中使用:/smile.png访问到文件资源:

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    QString title = this->windowTitle();
    qDebug() << title;

    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;

    // : 访问qrc管理的资源, / 就是前缀
    QIcon winIcon(":/smile.png");
    this->setWindowIcon(winIcon);
}

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

|huge


QT Creator实际是将被qrc管理的文件资源, 以二进制形式编译进了可执行程序中

build-xxxxx的子目录下可以看到qrc相关的.cpp文件:

这个数组, 就是文件的二进制数据, 数组的每一个元素都是1字节unsigned char

此文件, 在QT Creator编译代码时 会一同编译进可执行程序中

qrc机制更适合于小文件资源, 如果太大, 不适合直接被加载到可执行程序中, 只会造成性能损耗

windowOpacity Link to windowOpacity

此属性, 用于设置窗口的不透明度, 且此属性同样对独立窗口有效

QT提供了两个相关的接口:

接口功能
qreal windowOpacity() const;获取窗口当前的不透明度
void setWindowOpacity(qreal level);设置窗口的不透明度

qreal实际就是double类型, 所以 使用也很简单:

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    QString title = this->windowTitle();
    qDebug() << title;

    this->setWindowTitle("这是一个窗口标题");
    title = this->windowTitle();
    qDebug() << title;

    QIcon winIcon(":/smile.png");
    this->setWindowIcon(winIcon);

    btn1 = new QPushButton(this);
    btn1->setGeometry(300, 210, 200, 40);
    btn1->setText("按钮1: +");
    connect(btn1, &QPushButton::clicked, this, &Widget::btn1ClickedHandler);

    btn2 = new QPushButton(this);
    btn2->setGeometry(300, 330, 200, 40);
    btn2->setText("按钮2: -");
    connect(btn2, &QPushButton::clicked, this, &Widget::btn2ClickedHandler);
}

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

void Widget::btn1ClickedHandler() {
    qreal winOpacity = this->windowOpacity();
    if (winOpacity > 1) {
        return;
    }

    this->setWindowOpacity(winOpacity + 0.05);

    qDebug() << this->windowOpacity();
}

void Widget::btn2ClickedHandler() {
    qreal winOpacity = this->windowOpacity();
    if (winOpacity < 0) {
        return;
    }

    this->setWindowOpacity(winOpacity - 0.05);

    qDebug() << this->windowOpacity();
}

这段代码的运行结果为:

从结果可以看到, windowOpacity这个属性, 是自带范围控制的[0, 1]

不建议把不透明度设置为0, 窗口会变成无法选中状态

cursor Link to cursor

此属性, 用于设置控件范围内光标的样式

光标就是这个东西:

|medium

QT可以设置光标在控件范围时的光标形式, 可以在QT Designer中直接选择控件进行设置, 也可以通过代码的方式进行设置

设置Widgetcursor上箭头, pushButtoncursor等待

设置完之后, 运行结果如下:

|huger

也可以通过代码进行设置, QT提供了相应的接口

接口功能
QCursor cursor() const;获取控件当前光标样式
void setCursor(const QCursor &);设置控件的光标样式
void QGuiApplication::setOverrideCursor(const QCursor& cursor);设置全局光标样式, 对整个程序中所有的控件生效, 会覆盖setCursor()设置的样式

QCursor是一个光标类, 可以用来设置控件的cursor属性

widget.cc:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>

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

    QCursor csr(Qt::CrossCursor);
    this->setCursor(csr);

    csr = Qt::IBeamCursor;
    ui->pushButton->setCursor(csr);
}

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

程序运行结果为:

|huger

QT提供了许多的cursor类型, 都可以在QCursor对象中设置:

|huger

自定义光标样式 Link to 自定义光标样式

除了内置的光标样式之外, QT还能够自定义光标样式

可以使用图片, 作为控件的光标样式, 接口还是setCursor(), 参数也还是QCursor类型

但是, QCursor对象的实例化就不能是enum CursorShape

需要使用图片资源实例化QCursor对象:

接口功能
QCursor(const QPixmap &pixmap, int hotX=-1, int hotY=-1);以图片资源QPixmap实例化QCursor对象的构造函数

QPixmap类, 就是用于使用图片资源的类, 使用图片之前可以用qrc将图片资源管理起来

|huge

widget.cc:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>

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

    QPixmap csrPic(":/heartWings.png");
    QCursor csr(csrPic);
    this->setCursor(csr);
    ui->pushButton->setCursor(csr);
}

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

程序运行的结果为:

|huger

在使用图片自定义光标时, 如果没有特殊情况 默认的有效点击位置是图片的左上角(0, 0)的位置, 有效点击位置被叫做热点

什么是特殊情况呢, 如果图片的(0, 0)位置是透明的, 就是特殊情况

此时, 光标的热点就会默认被设置为图片的中心位置(上面例子中使用的图片就是64x64的四周透明的png图片)

通过QCursor::hotSpot()可以查看光标的热点:

也可以在QCursor对象实例化时 构造函数传参设置光标的热点, 或通过成员函数setPos()设置光标的热点:

如果, 设置的热点位置超出了图片尺寸, 则光标热点会发生偏移:

font Link to font

此属性, 用于设置控件文本的字体样式

QT Designer可以直接设置控件的font属性, 并且在QT Designer中可以实时预览:

也可以通过代码的形式设置控件的font属性

QT的相关接口有:

接口功能
const QFont &font() const;获取控件当前文本的font属性
void setFont(const QFont &);设置控件文本的font属性

这两个接口的用法很简单, 使用了QFont

QFont类拥有一个字体的属性的成员, 通过设置QFont对象的成员, 再调用setFont()就能实现对控件文本的font属性的设置

QFont拥有许多的成员, 不过不用一一了解, 通常只需要了解一些常用的接口来设置font常用属性就可以了

font的常用属性已经在QT Designer中展示出来了:

字体族(font-family) 点大小(point-size) 粗体(bold) 斜体italic 下划线(underline) 删除线(strikeout) 字距调整(kerning)

点大小设置的就是字体大小

还有另外常用的: 字体风格(style) 字体宽度(weight)

这些都可以通过QFont的成员函数获取或设置, 下面只罗列设置:

接口功能
void setFamily(const QString &);设置字体族, 即 什么字体, 通常需要保证系统中已安装
void setPointSize(int);设置字体大小
inline void setBold(bool);设置是否粗体
inline void setItalic(bool);设置是否斜体
void setUnderline(bool);设置是否有下划线
void setStrikeOut(bool);设置是否有删除线
void setKerning(bool);设置是否调整字体间距
void setStyle(Style style);设置字体风格, 与 字体粗细 倾斜等有关
void setWeight(int);设置字体宽度, 与 字体粗细有关

QFont对象设置这些属性, 可以设置一个字体风格

若需要使用字体文件设置字体族, 则需要使用其他接口设置一个QString表示字体族

然后再调用setFamily()设置字体族

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QFont>

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

    QFont fonts;
    fonts.setFamily("FiraCode Nerd Font"); // 设置 字体族
    fonts.setPointSize(14);				   // 设置 字体大小14
    fonts.setBold(true);				   // 开启 粗体
    fonts.setItalic(false);				   // 关闭 斜体
    fonts.setUnderline(false);			   // 关闭 下划线
    fonts.setStrikeOut(true);			   // 开启 删除线
    fonts.setKerning(true);				   // 关闭 字距调整

    ui->label->setFont(fonts);
    ui->label->setText("This is a QLabel.");
}

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

程序的执行结果为:

tooltip Link to tooltip

此属性, 用于设置光标悬停在控件上时, 给出的提示

什么意思呢, 举个例子:

|lwide

这样的提示就是tooltip可以显示的内容

QT Designer中有相关的设置:

也可以直接通过代码设置, QT相关的接口有:

接口功能
QString toolTip() const;获取控件当前的tooltip
void setToolTip(const QString &);设置控件的tooltip
int toolTipDuration() const;获取控件当前tooltip的持续显示时间, 单位ms
void setToolTipDuration(int msec);设置控件tooltip的持续显示时间, 单位ms

PushButton设置tooltip: “这只是一个什么用都没有的按钮”, 持续显示时间为5000ms

widget.cc:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "widget.h"
#include "ui_widget.h"

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

    ui->pushButton->setToolTip("这只是一个什么用都没有的按钮");
    ui->pushButton->setToolTipDuration(5000);
}

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

程序运行结果为:

|huger

focusPolicy Link to focusPolicy

此属性, 用于设置控件的聚焦方式

要理解聚焦方式, 首先要理解聚焦, 什么是聚焦?

在上网的过程中, 一定遇到过各种登录的场景, 比如:

|small

在需要从键盘输入数据时, 需要先点击单行文本编辑框, 将输入焦点聚焦在单行文本编辑框上

然后才能将文本输入到聚焦的单行文本编辑框中:

并且, 可以通过点击或Tab的方式, 切换所聚焦的单行文本编辑框:

focusPolicy就是设置这些控件的聚焦方式

Qt::FocusPolicy是一枚举类型:

CPP
1
2
3
4
5
6
7
enum FocusPolicy {
    NoFocus = 0, 								// 不接收键盘焦点, 即 无法聚焦
    TabFocus = 0x1,								// 可以且只能通过Tab键获取焦点
    ClickFocus = 0x2,							// 可以且只能通过点击获取焦点
    StrongFocus = TabFocus | ClickFocus | 0x8,	// 可以同时通过Tab或点击获取焦点
    WheelFocus = StrongFocus | 0x4 				// 还可以通过滚轮滚动获取焦点
};

QT Designer创建5个单行文本编辑框, 并分别设置为:

NoFocus TabFocus TabFocus ClickFocus StrongFocus

执行结果为:

|huger

代码实现QT相关的接口有:

接口功能
Qt::FocusPolicy focusPolicy() const;获取控件当前聚焦方式
void setFocusPolicy(Qt::FocusPolicy policy);设置控件的聚焦方式

用代码的方式, 实现与上面相同的效果:

可以在QT Designer修改各lineEidtobjectName为:

lineEdit_noFocus lineEdit_tabFocus_1 lineEdit_tabFocus_2 lineEdit_clickFocus lineEdit_strongFocus

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    ui->lineEdit_noFocus->setFocusPolicy(Qt::NoFocus);
    qDebug() << ui->lineEdit_noFocus->focusPolicy();

    ui->lineEdit_tabFocus_1->setFocusPolicy(Qt::TabFocus);
    qDebug() << ui->lineEdit_tabFocus_1->focusPolicy();

    ui->lineEdit_tabFocus_2->setFocusPolicy(Qt::TabFocus);
    qDebug() << ui->lineEdit_tabFocus_2->focusPolicy();

    ui->lineEdit_clickFocus->setFocusPolicy(Qt::ClickFocus);
    qDebug() << ui->lineEdit_clickFocus->focusPolicy();

    ui->lineEdit_strongFocus->setFocusPolicy(Qt::StrongFocus);
    qDebug() << ui->lineEdit_strongFocus->focusPolicy();
}

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

运行结果为:

styleSheet Link to styleSheet

此属性, 用于设置控件的QSS样式

QSS样式是QT中一种类似CSS的东西

CSS在网页前端的开发中是必备的, 它一般长这样:

|lwide

由标签和其所拥有的若干的键值对组成, 设置网页元素的风格, 用于网页元素的渲染

QSS的语法与CSS高度相似, 不过在更复杂场景又存在不同

QSS也可以通过标签+键值对的方式, 设置控件的风格, 具体语法不多介绍

只需要知道QT可以通过类似CSSQSS设置控件的风格了

QT Designer中, 可以直接对控件进行QSS风格设置:

比如:

CSS
1
2
3
4
5
background-color: rgb(255, 255, 127);
color: rgb(255, 0, 0);
font-family: "FiraCode Nerd Font";
font-weight: 800;
font-size: 16pt;

运行, 并输入文本:

|huge

如果要通过代码实现, QT相关的接口有:

接口功能
QString styleSheet() const获取控件当前的styleSheet
void setStyleSheet(const QString& styleSheet);设置控件的styleSheet

获取和设置都以QString作为对象

用代码的方式实现上面的效果:

widget.cc:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

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

    qDebug() << ui->textEdit->styleSheet();
    ui->textEdit->setStyleSheet("background-color: rgb(255, 255, 127); color: rgb(255, 0, 0); font-family: 'FiraCode Nerd Font'; font-weight: 800; font-size: 16pt;");
    qDebug() << ui->textEdit->styleSheet();
}

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

通过setStyleSheet()设置控件的QSS格式, 只需要以QString的形式将键值对传入其中就可以了

运行结果为:

日间与夜间模式(小玩具程序) Link to 日间与夜间模式(小玩具程序)

QT Designer:

|huge

widget.h:

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
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
    class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT

public:
    Widget(QWidget* parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget* ui;
    bool isNight;
};
#endif // WIDGET_H

widget.cc:

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
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , isNight(false) {
    ui->setupUi(this);
        
    ui->textEdit->setStyleSheet("font-family: 'FiraCode Nerd Font'; font-size: 16pt;");
}

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

void Widget::on_pushButton_clicked() {
    if (isNight) {
        // 当前为夜间模式, 需要设置为日间模式
        this->setStyleSheet("background-color: rgb(240, 240, 240); color: black;");
        ui->textEdit->setStyleSheet("background-color: white; color: black; font-family: 'FiraCode Nerd "
                                    "Font'; font-size: 16pt;");
        ui->pushButton->setText("夜间模式");

        isNight = false;
    }
    else {
        // 当前为日间模式, 需要设置为夜间模式
        this->setStyleSheet("background-color: rgb(36, 39, 58); color: rgb(202, 211, 245);");
        ui->textEdit->setStyleSheet("background-color: rgb(36, 39, 58); color: rgb(202, 211, 245); font-family: 'FiraCode Nerd "
                                    "Font'; font-size: 16pt;");
        ui->pushButton->setText("日间模式");

        isNight = true;
    }
}

运行结果:

|huge


上面就是QWidget最常用的一些属性, QT中所有的控件基本都是从QWidget继承出来的

所以, 相关控件都拥有QWidget的一些属性, 在后续其他控件的介绍中, 就可以直接使用

要了解更多, 可以查看QT文档

感谢阅读~

Thanks for reading!

[QT5] 常用控件: QWidget是什么? 了解 控件常用公共属性, QT的qrc资源管理机制...

Mon Dec 16 2024
6094 字 · 37 分钟