QT(超详细从0开始)

目录

[1.2 Qt的优点](#1.2 Qt的优点)

2.安装Qt

3.创建项目

4.解读Qt自动生成的代码

​编辑

[5.Qt Designer](#5.Qt Designer)

6.Qt对象数

7.Qt乱码问题

8.Qt坐标系的认识

9.信号和槽

[9.1 connect](#9.1 connect)

[9.2 自定义槽函数](#9.2 自定义槽函数)

[9.3 自定义信号](#9.3 自定义信号)

[9.4 断开信号链接(disconnect)](#9.4 断开信号链接(disconnect))

9.5.lambda表达式

10.常用控件的介绍以及使用

[10.1 QWidget](#10.1 QWidget)

[10.1.1 QWidget的enable属性](#10.1.1 QWidget的enable属性)

[10.1.2 QWidget的geometry属性](#10.1.2 QWidget的geometry属性)

[10.1.3 WindowFrame的影响](#10.1.3 WindowFrame的影响)

[10.1.4 QWidget的windowTitle属性](#10.1.4 QWidget的windowTitle属性)

[10.1.5 QWidget的windowlcon属性](#10.1.5 QWidget的windowlcon属性)

[10.1.6 QWidget的WindowOpacity属性](#10.1.6 QWidget的WindowOpacity属性)

[10.1.7 QWidget的cursor属性](#10.1.7 QWidget的cursor属性)

[10.1.8 QWidget的font属性](#10.1.8 QWidget的font属性)

[10.1.9 QWidget的toolTip属性](#10.1.9 QWidget的toolTip属性)

[10.1.10 QWidget的focusPolicy属性](#10.1.10 QWidget的focusPolicy属性)

[10.1.11 QWidget的styleSheet属性](#10.1.11 QWidget的styleSheet属性)

[10.2 Button按键](#10.2 Button按键)

[10.2.1 QPushButton添加图标](#10.2.1 QPushButton添加图标)

[10.2.2 QPushButton添加快捷](#10.2.2 QPushButton添加快捷)

[10.2.3 QRadioButton的使用](#10.2.3 QRadioButton的使用)

[10.2.4 QCheckBox的使用](#10.2.4 QCheckBox的使用)

[10.3 QLabel](#10.3 QLabel)

[10.3.1 QLanel文本显示方式](#10.3.1 QLanel文本显示方式)

[10.3.2 QLanel设置图片](#10.3.2 QLanel设置图片)

[10.3.3 QLabel设置自动换行,边距,缩进](#10.3.3 QLabel设置自动换行,边距,缩进)

[10.3.4 QLabel设置伙伴](#10.3.4 QLabel设置伙伴)

[10.4 QLCDNumber](#10.4 QLCDNumber)

[10.5 ProgressBar](#10.5 ProgressBar)

[10.6 QCalendarWidget](#10.6 QCalendarWidget)

[10.7 QLineEdit](#10.7 QLineEdit)

[10.7.1 QLineEdit的使用](#10.7.1 QLineEdit的使用)

[10.7.2 QLineEdit属性](#10.7.2 QLineEdit属性)


1.QT的诞生史

Qt 是一个跨平台的 C++ 应用程序开发框架,由挪威的 Trolltech 公司创立。以下是 Qt 的主要发展历程:

1.创建阶段(1991-1992年):

Qt 开始于 1991 年,最初是为了满足挪威电讯公司(Telenor)的内部需要而开发的。Trolltech 公司的创始人之一 Haavard Nord和Eirik Chambe-Eng,都是在Telenor工作时开发了 Qt。1992 年 Trolltech 公司正式成立,将 Qt 作为主要的产品和开发平台。

2.商业化(1994 年):

Trolltech 公司推出了 Qt 1.0 版本,正式将其作为商用软件发布。Qt 1.0 支持 X11,但在 Windows 平台上尚未提供支持。

3.跨平台支持(1995年):

Qt 2.0 在 1995 年发布,这是 Qt 第一个支持跨平台开发的版本,同时在 Windows 和 X11 上实现了兼容。这使得开发者可以编写一次代码,然后在不同的平台上进行部署而无需大量修改。

4.开源化(1999年):

Trolltech 公司于 1999 年将 Qt 开源,并发布了 Qt 2.3 版本。这一举措使得开发人员可以自由获取和使用 Qt,加速了 Qt 在各种平台上的普及。

5.KDE 的采用(2000年):

KDE(K Desktop Environment)是一个流行的 Linux 桌面环境,于 2000 年开始采用 Qt 作为主要的开发工具包,这加速了 Qt 在 Linux 社区的普及。

6.版本升级(2005年和之后):

随着时间的推移,Qt 经历了多个主要版本的升级和更新,不断增加新的功能和改善性能。Qt 4 和 Qt 5 版本的发布进一步提升了 Qt 在跨平台应用程序开发中的地位。

7.The Qt Company(2012年):

2012 年,Digia 公司收购了 Trolltech 公司,并在 2013 年将 Qt 的开发部门和知识产权转移到了一个新成立的公司,The Qt Company。

8.当前阶段(2021年):

到了今天,Qt 仍然是一个广受欢迎的跨平台开发框架,在不同领域中得到广泛应用,包括桌面应用程序、移动应用程序、嵌入式系统等。The Qt Company 不断推出新版 Qt,提供各种工具和服务来支持开发者的需求,可以说现在的Qt是一位六边形战士。

Qt 的发展经历了多个重要里程碑,一直以来都是开发人员和组织中的首选框架之一,对于跨平台应用程序开发起到了重要的推动作用。

1.2 Qt的优点

* 跨平台,几乎支持所有的平台

* 接口简单,容易上手,学习QT框架对学习其他框架具有很高的参考意义

* 一定程度上简化了内存回收机制

* 开发效率高,能够快速的啊构建应用程序

* 有很好的社区氛围,市场份额在缓慢上升

* 可以进行嵌入式编程

2.安装Qt

其他的方式安装这里并不是很推荐,我们可以直接下载Qt Creator,它已经配置好了所需的编译器以及其他,并不需要我们去手动配置

以下是下载Qt Creator的网址,下载安装即可,一路next下去即可,并没有什么难度

Index of /archive/qt/5.12/5.12.12

3.创建项目

下载安装完成后,我们将会得到这样一个页面

接下来,我们一步一步去创建一个项目

并没有什么难度

4.解读Qt自动生成的代码

//自定义窗口部件的头文件,widget类定义了应用程序的主窗口,其包含
//用户界面和其它江湖元素
#include "widget.h"
//这是我们之前选择QApplication,自己包含的头文件
#include <QApplication>

int main(int argc, char *argv[])
{
//创建一个QApplication对象a,它是Qt应用程序的主要对象
//注:负责处理时间循环和应用程序的整体管理
    QApplication a(argc, argv);
//创建一个Widget对象w
//注:调用其构造函数来初始化窗口控件
    Widget w;
//显示窗口控件,与之对应的w.hide()关闭显示
    w.show();
//启动Qt事件循环,处理用户触发事件,或者定时器等
//exec会一直运行至程序终止,结束后会返回程序状态码
    return a.exec();
}

此处是一段简单的Qt程序入口函数,此处创建了一个应用程序对象,自定义窗口控件对象,并最终通过事件循环来驱动整个程序的运行。

直接进入Widget的声明中,我们接着去看。

//防止头文件重复包含,自不必多说
#ifndef WIDGET_H
#define WIDGET_H
//QWidget:创建Qt中控件的基类
#include <QWidget>
//QT_BEGIN_NAMESPACE,QT_END_NAMESPACE:用于定义命名空间,在这个命名空间中
,定义了一个名为ui的命名空间,其中包含一个名为Widget的类。
QT_BEGIN_NAMESPACE
//此处是由 Qt Designer 自动生成,后续会解释什么是 Qt Designer 
namespace Ui { class Widget; }
QT_END_NAMESPACE

//Widget类的声明,他继承自Qwidget,表示Widget是一个窗口控件类
//窗口控件:是用户界面的基本组成部分,用于创建和管理用户界面上的各种元素
class Widget : public QWidget
{
//Qt元对象宏,类中声明一个Qt元对象类。
//这个宏使得该类可以使用信号以及槽机制和其他元对象相关的功能
//注:Qt中很多地方都使用了元编程,所谓的元编程,就是代码生成代码的一种编码手段
    Q_OBJECT

public:
//widget的构造函数和析构函数
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
//声明私用成员Ui::Widget *ui;
    Ui::Widget *ui;
};
#endif // WIDGET_H
//Widget类的头文件,包含Widget的声明
#include "widget.h"
//包含ui_widget的头文件,是由Qt Designer自动生成的UI头文件
//其中包含一个名为Widget的类,该类包含了UI界面中的所有控件
#include "ui_widget.h"
//widget的构造函数,接收一个QWidget类型的指针作为参数,表示该窗口控件的父类
//在构造函数初始化列表中,首先调用了QWidget类的构造函数,将parent参数传递给
//基类构造函数,然后产生新的Ui::Widget对象,并将其指针赋值给成员变量ui
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
//调用ui所指向的对象setupUi()函数,将当前窗口的空间对象this作为参数传递给该函数。
//setupUi()函数是由Qt Designer自动生成的,用于初始化UI界面中的空间。包括布局,控件大小,位置等
    ui->setupUi(this);
}
//析构函数
Widget::~Widget()
{
//释放资源,首先通过delete ui 释放之前构造函数动态分配对象ui 所占的内存空间
    delete ui;
}

5.Qt Designer

Qt Designer 是一种可视化界面设计器,用于创建和设计Qt应用程序的用户界面,它允许开发人员通过拖放的操作来快速构建用户界面。无需手动操作,省去了大量代码。Qt Designer集成在Qt Creator 中,是Qt开发环境的一部分。

使用Qt Designer开发,可以轻松完成设计界面布局,添加控件,设置属性和信号槽连接等。Qt Designer 提供了一个直观地用户界面,是的开发人员可以以所见即所得的方式进行界面设计。并且可以实时预览效果。

Qt Designer主要包括以下功能:

1.托方式设计:通过简单的拖放操作,可以快速地将各种控件添加到界面中,并调整它们的大小,位置等

2.属性编辑:可以方便地编辑控件属性,如文本内容,颜色,字体等

3.信号槽编辑:可以直观地设置控价之间的信号槽连接,以实现界面元素之间的交互功能。

4.预览模式:可以实时预览设计效果,以便及时调整和修改

5.自定义控件:可以创建自定义部件和控价,并在界面中使用

6.支持国际化:提供了国际化工具,可以方便进行多种语言界面设计

点击之后我们将得到这样一个界面

6.Qt对象数

Qt 对象树是指在 Qt 应用程序中,各个 QObject 类型对象之间的层次结构关系。在 Qt 中,几乎所有的类都直接或间接继承自 QObject 类,因此 Qt 应用程序中的对象通常都是 QObject 类型的。

就比如我们的Qwidget也是继承自QObgect

Qt 对象树的特点包括:

1.层次结构关系:Qt 对象按照父子关系构成层次结构,形成了树形结构。每个 QObject 对象都可以有一个父对象,也可以有多个子对象。当一个对象被设置为另一个对象的子对象时,它会自动成为后者的子节点,形成层次结构。

2.资源管理:Qt 对象树的存在方便了资源的管理和释放。当父对象被销毁时,它会自动销毁所有的子对象,从而避免了内存泄漏和资源泄漏的问题。这是通过 Qt 中的对象树自动回收机制实现的。

3.信号与槽传播:QObject 类提供了信号与槽机制,用于对象之间的通信。在对象树中,信号和槽的连接可以跨越父子对象之间的边界,使得对象之间的通信更加灵活。

4.对象查找:Qt 提供了一系列方法用于在对象树中查找特定对象,包括通过对象名称、类型、父对象等条件进行查找。

5.父子关系的影响:父子关系不仅影响对象的生命周期管理,还影响了对象的事件传递和属性继承。例如,当父对象接收到事件时,它会将事件传递给所有的子对象;父对象的属性更改也可能会影响到子对象。

在 Qt 应用程序中,通常会利用对象树的特性来组织和管理界面控件、数据模型、线程对象等各种对象,从而实现清晰的代码结构和有效的资源管理。

7.Qt乱码问题

在Qt中提供了很多和c++语法相同的关键字,唯一不同的是在前面加了q,这是一些历史遗留问题,当然,qt中也支持你使用c++的关键字,因为对其本身并没有影响,所以并没有去解决这块问题。相反,当你熟悉Qt还会感觉无比舒服看起来。

在Qt中我们通常不会使用cout等流插入方式进行打印我们的错误信息,而是使用qDebug()来打印,一方面:是因为cout编码一般会因为你的设备不同而格式不同,在windows中通常是 Windows ANSI 编码(例如,CP1252)。而在linux/Unix中则为UTF-8 编码。但在我们的Qt中一般默认输出的是UTF-8,所以我们使用cout打印可能会出现乱码情况。

另一方面:是因为在使用qDebug()打印,可以直接打印Qt的一些内置类型。这样使我们在编码中能够以更加高效和快速。

在 Qt Creator 中使用 qDebug() 打印中文字符时,如果编译器报错,可能有以下几个原因:

1.编码问题:确保源文件的编码格式正确。通常情况下,Qt Creator 默认使用 UTF-8 编码。如果源文件的编码格式不正确,可能会导致中文字符无法正确识别,从而引发编译器报错。

2.头文件包含:确保头文件中包含了正确的编码声明。在源文件的开头,可以添加类似于 #pragma execution_character_set("utf-8") 的声明,以确保编译器正确地处理中文字符。

3.Qt 版本问题:某些旧版本的 Qt 可能对中文字符的处理存在问题。确保您使用的是较新的 Qt 版本,以获得更好的中文字符支持。

4.编译器设置:有时,编译器的设置可能会影响对中文字符的处理。确保编译器的语言环境设置正确,并且支持 UTF-8 编码。

5.字符串转换:如果在 qDebug() 中直接输出中文字符串而没有进行适当的转换,可能会导致编译器报错。您可以尝试将中文字符串转换为 UTF-8 格式,然后再输出。

6.使用转义字符:在某些情况下,直接在代码中使用中文字符可能会导致编译器报错。您可以尝试使用 Unicode 转义字符来表示中文字符,例如 \u4E2D\u6587 表示中文字符 "中文"。

可能是编译器的原因,此处并未找到具体原因,不过可以使用英文打印,在编码中我们尽量多使用英文作为打印主流。

8.Qt坐标系的认识

对于坐标系,我们已经十分熟悉了,但在计算中的坐标系和数学中的坐标系略有不同。

9.信号和槽

在Qt中我们将用户的操作抽象为信号,而槽则是我们处理这种信号的逻辑。讲起信号与槽我们就不得不提到连接他们的一个函数connect

9.1 connect

接下来,我们创建一个按钮,将其连接一个点击信号触发,自定义一个槽来打印一些文字。

9.2 自定义槽函数

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->setupUi(this);
    //生成一个button,指定它的父元素this,也就是Widget
   QPushButton* button = new QPushButton(this);
   button->setText("按钮");
   connect(button, &QPushButton::clicked, this,  &Widget::HandleCilck);
}

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

//定义槽函数
void Widget::HandleCilck()
{
    qDebug() << "Button press";
}

widget.h

#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();
    //槽函数声明,在QT5以上版本可不写slots,但为区分还是可以将其写上
public slots:
    void HandleCilck();
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

9.3 自定义信号

我们将上面的代码进行修改,让它每次点击发送一个信号,通过关联这个信号去打印一段文字。

#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();
    //槽函数声明,在QT5以上版本可不写slots,但为区分还是可以将其写上
public slots:
    void HandleCilck();
    void HandleCreateSign();
        //signals:声明信号的关键字
signals:
    //我们只需要声明信号,Qt会自动生成信号的定义,并不需要我们定义
    void CreateSign();
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->setupUi(this);
    //生成一个button,指定它的父元素this,也就是Widget
   QPushButton* button = new QPushButton(this);
   button->setText("按钮");
   connect(button, &QPushButton::clicked, this,  &Widget::HandleCilck);
   connect(this, &Widget::CreateSign, this, &Widget::HandleCreateSign);
}

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

//定义槽函数
void Widget::HandleCilck()
{
//    qDebug() << "Button press";
    //这次我们不直接打印,我们发送信号,让其接收到我们自定义的信号,再进行打印
    emit CreateSign();
}
void Widget::HandleCreateSign()
{
    qDebug() << "Custom signals";
}

这里我们就通过按钮点击信号发送我们自定义的信号,接收到我们自定义的信号之后打印一段文字。

注:自定义的信号和槽是可以接收传参的,信号和槽也是可以以多对多的方式进行连接的,同一个信号可以可以被多个槽函数处理,同样的同一个槽可以被多个信号触发。

9.4 断开信号链接(disconnect)

我们创建两个按钮,点击按钮1打印一段文字,点击按钮2断开按钮1信号

#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();
    //槽函数声明,在QT5以上版本可不写slots,但为区分还是可以将其写上
public slots:
    void HandleCilck();
    void HandleDisCilck();
private:
    Ui::Widget *ui;
    //为了能让第二个断开槽函数访问到第一个按钮,我们直接将它变为成员函数
    QPushButton* button;
};
#endif // WIDGET_H

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QPushButton>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //生成一个button,指定它的父元素this,也就是Widget
   button = new QPushButton(this);
   button->setText("按钮1");
   //将Button这个按钮移动到(100,100)这个位置
   button->move(100,100);
   QPushButton* DisButton = new QPushButton(this);
   DisButton->setText("按钮2");
   DisButton->move(200,100);
   connect(button, &QPushButton::clicked, this,  &Widget::HandleCilck);
   connect(DisButton, &QPushButton::clicked, this,  &Widget::HandleDisCilck);
}

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

void Widget::HandleCilck()
{
    qDebug() << "Button press";
}
void Widget::HandleDisCilck()
{
    //断开连接
    //disconnect的使用方法和connect的使用方式一致
    bool link = disconnect(button, &QPushButton::clicked, this,  &Widget::HandleCilck);

    //断开成功返回true(0),我们可以通过返回值让它重新连接
    if(!link)
    {
        qDebug() << "Button reconnection";
        connect(button, &QPushButton::clicked, this,  &Widget::HandleCilck);
    }
    else
    {
        qDebug() << "Button Disconnected";
    }
}

运行后,我们可以通过按钮2l来控制按钮1的连接和断开,加上打印我们更能清楚看到

9.5.lambda表达式

在Qt我们同样可以使用lambda表达式,对一些代码逻辑和处理信号不是那么复杂的信号进行处理。

    QPushButton* LambdaButton = new QPushButton(this);
    //lambda表达式语法:()[]{处理逻辑}
    LambdaButton->setText("Lambda");
    connect(LambdaButton, &QPushButton::clicked, this,[](){
        qDebug() << "lambda";
    });

10.常用控件的介绍以及使用

10.1 QWidget

10.1.1 QWidget的enable属性

enable,setEnable:获取和禁用控件。我们创建一个按钮,通过setEnable禁用它。

    QPushButton* LambdaButton = new QPushButton(this);
    //lambda表达式语法:()[]{处理逻辑}
    LambdaButton->setText("Lambda");
    connect(LambdaButton, &QPushButton::clicked, this,[](){
        qDebug() << "lambda";
    });
    //false表示禁用,true启用
    LambdaButton->setEnabled(false);

效果如下:

按键变成灰色,无法进行点击。

10.1.2 QWidget的geometry属性

geometry,setGeometry获取和设置控件大小,位置

geometry 属性的结构如下:

  • x:窗口部件左上角的 x 坐标。
  • y:窗口部件左上角的 y 坐标。
  • width:窗口部件的宽度。
  • height:窗口部件的高度。

通过设置窗口部件的 geometry 属性,可以将其放置在窗口中的任意位置,并指定其大小。

    QPushButton* LambdaButton = new QPushButton(this);
    //lambda表达式语法:()[]{处理逻辑}
    LambdaButton->setText("Lambda");
    connect(LambdaButton, &QPushButton::clicked, this,[](){
        qDebug() << "lambda";
    });
    //false表示禁用,true启用
    LambdaButton->setEnabled(false);

    //返回值是一个QRect
    QRect rect = LambdaButton->geometry();
    //设置控件大小
    //可以传入一个QRect类型,也可以直接复制
    LambdaButton->setGeometry(500, 500, 100, 100);

运行结果如下:

10.1.3 WindowFrame的影响

在Qt中,WindowFrame是一个窗口部件(QWidget)的属性,它控制着窗口部件周围的边框和装饰,设置WindowFrame的值可以影响窗口的外观和行为。

当windowFrame设置为 true 时,窗口部件将显示标准的窗口边框和装饰,包括标题栏,边框和窗口按钮(最大化,最小化,关闭等)。通常用于创建独立的,可移动的窗口的情况。

当windowFrame设置为 false 时,窗口部件将不再显示标准的窗口边框和装饰,而仅显示窗口本身内容,通常用于创建自定义的,非模态的对话框或小部件,以便将嵌入式到其他界面中。

10.1.4 QWidget的windowTitle属性

windowTitle,setWindowTitle获取和设置窗口标题

//设置窗口标题为Window Frame Example
    this->setWindowTitle("Window Frame Example");

运行结果:

10.1.5 QWidget的windowlcon属性

windowlcon,setwindowIcon获取设置窗口LOGO

使用这个函数我们需要准备一张图片作为它的LOGO,因为部分情况下用户会将图片删除,导致程序无法正常运行,Qt中引入一个将图片进行二进制编码的过程,将图片加入到代码中,优点是,数据不容易丢失。缺点是,生成的可执行程序会较大,所以不建议将视频也进行编码。

具体操作如下:

    //加载图片
    QIcon WidgetMoon(":/moon.png");
    //设置Widget的LOGO
    this->setWindowIcon(WidgetMoon);

运行结果:

给大家推荐一个下载图片的网址:阿里巴巴矢量图

iconfont-阿里巴巴矢量图标库

这是一个开源的图库,里面内容相对较为丰富。

10.1.6 QWidget的WindowOpacity属性

WindowOpacity,setWindowOpacity设置透明度,

我们创建两个按钮,分别控制其+透明度和-透明度

    QPushButton* AddButton = new QPushButton(this);
    QPushButton* MinusButton = new QPushButton(this);
    AddButton->setText("+");
    AddButton->setGeometry(200, 400, 100,100);
    connect(AddButton, &QPushButton::clicked, this, &Widget::HandleWidgetAddLucency);
    MinusButton->setText("-");
    MinusButton->setGeometry(500, 400, 100,100);
    connect(MinusButton, &QPushButton::clicked, this, &Widget::HandleWidgetMinusLucency);

void Widget::HandleWidgetAddLucency()
{

    float AddLucency = this->windowOpacity();
    //虽然每次设置都有判断,但为了出现意外情况,我们还是有必要
    //进行判断的
    if(AddLucency < 1)
    {
        //设置浮点数,按钮每次按下,将其+0.1
        //并设置QWidget的透明度
        AddLucency += 0.1;
        this->setWindowOpacity(AddLucency);
    }
}
void Widget::HandleWidgetMinusLucency()
{
    float MinusLucency = this->windowOpacity();
    if(MinusLucency > 0)
    {
        //设置浮点数,按钮每次按下,将其-0.1
        //并设置QWidget的透明度
        MinusLucency -= 0.1;
        this->setWindowOpacity(MinusLucency);
    }
}

效果如下:

10.1.7 QWidget的cursor属性

cursor,setCursor获取设置控件鼠标样式

通过Qt Designer我们可以看到其内置的鼠标样式,我们也可以通过鼠标点到我们想要查看的函数(如cursor)按F1,通过查看文档去了解其鼠标样式。

当然我们也可以自定义鼠标样式,首先加载图片,步骤已经说过,就不再赘述。如若不会可跳转至"10.1.5 QWidget的windowlcon属性"查看具体操作步骤。

选择已经下载好的文件,进行添加

    //此处不能用QIcon加载光标图片,类型不匹配
//    QIcon CursorBasketball(":/basketball.png");
    //只能使用QPixmap
    QPixmap CursorBasketball(":/basketball.png");
    
    QCursor cursor(CursorBasketball);
    this->setCursor(cursor);

如果只是这样设置,你会发现光标的大小以及热点(hotspot)并不是很理想

注:此处热点,并非我们手机打开的热点,而是光标点击生效的位置

    //此处不能用QIcon加载光标图片,类型不匹配
//    QIcon CursorBasketball(":/basketball.png");
    //只能使用QPixmap
    QPixmap CursorBasketball(":/basketball.png");
    //设置图片大小
    CursorBasketball = CursorBasketball.scaled(100,100);
    QCursor cursor(CursorBasketball);
    //还原默认光标
    //QApplication::restoreOverrideCursor();
    this->setCursor(cursor);
10.1.8 QWidget的font属性

font,setFont获取和设置字体属性(包括字体,字号,加粗,切斜等)

在Qt Designer中我们可以清楚的看到

当我们通过Qt Designer中创建一个Label将它的字体大小等信息全部设置后,我们将看到

那我们用代码的方式实现,创建两个Label,一个不设置字体,一个同上设置为这种字体,运行代码我们来看结果。

//创建两个QLabel控件
    QLabel* Setlabel = new QLabel(this);
    QLabel* NoSettingsLabel = new QLabel(this);
    //设置位置大小等信息
    Setlabel->setGeometry(200,200, 400,100);
    Setlabel->setText("This is unset text");
    NoSettingsLabel->setGeometry(550,200,100,100);
    NoSettingsLabel->setText("This is the text after setting");
    //创建字体类型
    QFont font;
    font.setFamily("黑体");//设置字体家族
    font.setPointSize(20);//设置字号
    font.setBold(true);//设置粗体
    font.setItalic(true);//设置斜体
    font.setStyleStrategy(QFont::PreferAntialias); // 启用字体的锯齿线渲染策略
    font.setStrikeOut(true);//设置删除线
    Setlabel->setFont(font);//将配置到的信息加载进入

运行程序,我们将得到

10.1.9 QWidget的toolTip属性

toolTip,setToolTip获取设置控件的工具提示文本,当鼠标悬停置控件上一段时间会显示简短说明。比如:此处的橡皮擦。我们创建一个橡皮擦设置悬停后出现一段提示语。

    QLabel* EraserLabel = new QLabel(this);
    QPixmap pixmap(":/eraser.png");//加载图片
    EraserLabel->setPixmap(pixmap.scaled(40, 40));//设置图片以及图片大小
    EraserLabel->setGeometry(100,100,40,40);//设置部件位置,大小
    EraserLabel->setToolTip("This is an eraser");//设置鼠标悬停后的提示语
    QString tooltipText = EraserLabel->toolTip();//获取当前的提示文本
    qDebug() << tooltipText;
10.1.10 QWidget的focusPolicy属性

focusPolicy,setFocusPolicy获取设置焦点(用户界面中当前接收键盘输入的控件或部件)

在Qt Designer中有以下几种可供选择

在代码中可选值:

Qt::FocusPolicy枚举类型定义了focusPolicy属性的可选值:

* Qt::NOFocus(0):控件永远不会接受焦点。

* Qt::TabFocus(1):控件永远只会接受Tab键的焦点。

* Qt::ClickFocus(2):控件永远只会接受鼠标点击的焦点。

* Qt::StrongFocus(3):控件接受鼠标点击和Tab键的焦点

* Qt::WheelFocus:控件接受鼠标滚轮滑动的焦点。

注:默认情况下,大多数QWidget子类的focusPolicy属性都为NoFocus并不会接受焦点。

在Qt Designer中以下两种控件创建后,会接受焦点

其中Line Edit是单行输入,Text Edit和Plain Text Edit是多行输入.

创建三个Line Edit控件,分别将他们的属性设置为NOFocus,TabFocus和ClickFocus。

    QLineEdit* NoFocusEdit = new QLineEdit(this);
    QLineEdit* TabFocusEdit = new QLineEdit(this);
    QLineEdit* ClickFocusEdit = new QLineEdit(this);
    NoFocusEdit->setGeometry(100,100,200,40);
    TabFocusEdit->setGeometry(100,200,200,40);
    ClickFocusEdit->setGeometry(100,300,200,40);
    NoFocusEdit->setFocusPolicy(Qt::NoFocus);//无法获取焦点
    TabFocusEdit->setFocusPolicy(Qt::TabFocus);//鼠标无法无法获取焦点
    ClickFocusEdit->setFocusPolicy(Qt::ClickFocus);//Tab键无法获取焦点

运行结果:

10.1.11 QWidget的styleSheet属性

styleSheet,setStyleSheet获取设置控件样式和外观(允许使用CSS-like语法来设置和定制控件样式和外观,类似与Web开发中的CSS样式表,可以影响部件的背景,边框,字体和颜色等视觉方面的表现)

语法格式

widget->setStyleSheet("property: value; property2: value2; ...");

其中,property 是样式属性,value 是对应的属性值。多个属性之间用分号分隔。

创建一个Label设置它的styleSheet属性

    QLabel* StleSheetLabel = new QLabel(this);
    StleSheetLabel->setText("这是被设置后的Label");
    QRect rect = this->geometry();
    StleSheetLabel->setGeometry(rect.width() / 2, rect.height() / 2, 200, 100);
    //设置背景颜色为蓝色,rgba是三原色:rgba(red, green, blue, alpha)
    //其中alpha代表透明度0表示完全透明,1表示完全不透明
    //字体大小为16个像素
    //边框样式为2像素的红色表框
    StleSheetLabel->setStyleSheet("background-color:  rgba(00, 197, 209, 1); font-size: 16px; border: 2px solid red;");

运行结果

样式表可以通过选择器来选择特定的控件。如果我们只想给一个特定的控件设置样式,可以使用类选择器和ID选择器

QPushButton#myButton {
    background-color: blue;
    color: white;
}

#myButton 是按钮的ID选择器,表示样式适用于具有 myButton ID 的按钮。

属性设置: 样式表支持许多常见的CSS属性,例如:

还可以根据具体的QWidget类型和需求设置更多特定的样式属性。

background-color:设置元素的背景颜色

color:设置文本内容颜色

font-size:设置问题字体大小

border:设置元素边框样式

padding:设置元素边框与内容之间的空白区域

等等...

10.2 Button按键

10.2.1 QPushButton添加图标

使用图像文件作为图标(准备好图片,加载给按钮上即可)

    // 创建一个 QPushButton
    QPushButton *button = new QPushButton(this);
    button->setGeometry(100, 100, 100, 100);
    // 加载图标
    QIcon icon(":/Button.png");
    // 缩放图标
    QSize iconSize(100,100);
    // 设置按钮的图标
    button->setIcon(icon);
    // 更新图片大小
    button->setIconSize(iconSize);

运行结果

使用Qt中的Qt Designer拖放方式进行添加图标

运行后

10.2.2 QPushButton添加快捷

在Qt中按键也是可以使用快捷键按下的(QShortcut)

创建五个按键,其中四个按键分别控制上下左右,移动非上下左右的按键。

接下来,我们将他们绑定槽函数,以及添加快捷键。

    connect(ui->pushButton_down, &QPushButton::clicked, this, &Widget::HandleDownCilck);
    connect(ui->pushButton_up, &QPushButton::clicked, this, &Widget::HandleUpCilck);
    connect(ui->pushButton_left, &QPushButton::clicked, this, &Widget::HandleLeftCilck);
    connect(ui->pushButton_right, &QPushButton::clicked, this, &Widget::HandleRightCilck);

    // 直接通过按键的名字来设置. 虽然简单, 但是容易写错.
//    ui->pushButton_up->setShortcut(QKeySequence("ctrl + w"));
//    ui->pushButton_down->setShortcut(QKeySequence("s"));
//    ui->pushButton_left->setShortcut(QKeySequence("a"));
//    ui->pushButton_right->setShortcut(QKeySequence("d"));

    // 还可以通过按键的枚举来设置按键快捷键.
    // ui->pushButton_up->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W));
    ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_W));
    ui->pushButton_down->setShortcut(QKeySequence(Qt::Key_S));
    ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_A));
    ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_D));

    // 开启鼠标点击的连发功能(键盘的连发默认就是支持的)
    ui->pushButton_up->setAutoRepeat(true);
    ui->pushButton_down->setAutoRepeat(true);
    ui->pushButton_left->setAutoRepeat(true);
    ui->pushButton_right->setAutoRepeat(true);

void Widget::HandleUpCilck()
{
    QRect rect = ui->pushButton->geometry();
    ui->pushButton->setGeometry(rect.x(), rect.y() - 5, rect.width(), rect.height());
}
void Widget::HandleLeftCilck()
{
    QRect rect = ui->pushButton->geometry();
    ui->pushButton->setGeometry(rect.x() - 5, rect.y(), rect.width(), rect.height());
}
void Widget::HandleRightCilck()
{
    QRect rect = ui->pushButton->geometry();
    ui->pushButton->setGeometry(rect.x() + 5, rect.y(), rect.width(), rect.height());
}
void Widget::HandleDownCilck()
{
    QRect rect = ui->pushButton->geometry();
    ui->pushButton->setGeometry(rect.x(), rect.y() + 5, rect.width(), rect.height());
}

运行结果

此时我们的天猫汽车就可以动起来啦~

10.2.3 QRadioButton的使用

QRadioButton是Qt框架中用于创建单选按钮的类(当存在多个QRadioButton时,会出现互斥现象,也就是只能选择一个,如果我们想要多选,只能将他们做分组处理)

我们创建一个关于性别的按钮选项。

    Gender = new QLabel(this);
    Gender->setText("请选择你的性别:");
    Gender->setGeometry(200,180, 200 ,20);
//创建两个QRadioButton按钮
    ManRadioButton = new QRadioButton(this);
    WomanRadioButton = new QRadioButton(this);
    ManRadioButton->move(200,200);
    WomanRadioButton->move(200,230);
    ManRadioButton->setText("man");
    WomanRadioButton->setText("woman");
    connect(ManRadioButton, &QRadioButton::clicked, this, &Widget::HandleManRadioButtonClick);
    connect(WomanRadioButton, &QRadioButton::clicked, this, &Widget::HandleWomanRadioButtonClick);

void Widget::HandleManRadioButtonClick()
{

   Gender->setText("您选择的性别为man");
}
void Widget::HandleWomanRadioButtonClick()
{
   Gender->setText("您选择的性别为woman");
}

运行后:

在此按键中,我们还可以通过setChecked来设置默认选项

    //设置默认选项
    ManRadioButton->setChecked(true);
    Gender->setText("请选择你的性别:man");

完成后我们再次运行程序就会直接得到

并不需要点击触发。

当然在QRadioButton控件也有四种信号(clicked,pressed,released,toggled)

clicked:点击单选按钮时发出的信号

pressed:用户按下单选按钮时发出的信号

released:用户释放单选按钮时发出的信号

toggled:单选按钮的选中状态切换时发出的信号

如果我们想在同一个界面按下多个QRadioButton控件,就必须将他们进行分组(QButtonGroup)

    // 使用 QButtonGroup 对单选按钮进行分组
    QButtonGroup* group1 = new QButtonGroup(this);
    QButtonGroup* group2 = new QButtonGroup(this);
    QButtonGroup* group3 = new QButtonGroup(this);

    // 把上述单选按钮, 放到不同的组里.
    group1->addButton(ui->radioButton);
    group1->addButton(ui->radioButton_2);
    group1->addButton(ui->radioButton_3);

    group2->addButton(ui->radioButton_4);
    group2->addButton(ui->radioButton_5);
    group2->addButton(ui->radioButton_6);

    group3->addButton(ui->radioButton_7);
    group3->addButton(ui->radioButton_8);
    group3->addButton(ui->radioButton_9);

运行后

10.2.4 QCheckBox的使用

Qt 框架中用于创建复选框(checkbox)的类。复选框允许用户从多个选项中选择一个或多个。

使用方法基本同QRadioButton类似

    QVBoxLayout layout(this);

    // 创建多个复选框
    QCheckBox *checkBox1 = new QCheckBox("Option 1");
    QCheckBox *checkBox2 = new QCheckBox("Option 2");
    checkBox1->move(100,100);
    checkBox2->move(100, 150);
    // 添加复选框到布局中
    layout.addWidget(checkBox1);
    layout.addWidget(checkBox2);

    // 设置默认选中状态
    checkBox1->setChecked(true);

    // 连接信号和槽,处理选中状态变化
    QObject::connect(checkBox1, &QCheckBox::stateChanged, [&](int state) {
        if (state == Qt::Checked) {
            qDebug() << "Option 1 checked";
        } else {
            qDebug() << "Option 1 unchecked";
        }
    });

    QObject::connect(checkBox2, &QCheckBox::stateChanged, [&](int state) {
        if (state == Qt::Checked) {
            qDebug() << "Option 2 checked";
        } else {
            qDebug() << "Option 2 unchecked";
        }
    });

运行结果:

10.3 QLabel

10.3.1 QLanel文本显示方式

在Lanel控件中还提供了文本显示方式(纯文本,富文本,markdown文本)

具体他们有什么区别呢

我们使用Qt Designer创建三个Label控件,分别设置他们的文本

    // 把第一个 label 设置成显示纯文本.
    ui->label->setTextFormat(Qt::PlainText);
    ui->label->setText("# 这是一段纯文本");
    //把第二个 label 设置成显示富文本.
    ui->label_2->setTextFormat(Qt::RichText);
    ui->label_2->setText("<b>这是一段富文本</b>");
    //把第三个 label 设置成markdown文本.
    ui->label_2->setTextFormat(Qt::MarkdownText);
    ui->label_3->setText("# 这是一段markdown文本");

我们跳转到文本设置的枚举类型中,

PlainText:纯文本,标签默认支持这种格式。

RichText :富文本格式,Label 不支持此格式,但可以使用 RichTextBox 控件来显示富文本。

AutoText:自动检测文本格式并相应地显示。这需要自定义逻辑来识别文本格式并选择合适的控件进行显示。

MarkdownText :Markdown 格式,Label 不支持,但可以使用第三方库将 Markdown 转换为 HTML,然后使用 WebBrowser 控件显示。

10.3.2 QLanel设置图片

接下来,我们通过在Qt Designer中创建一个Label对象,然后加载一张图片,进行填充整个QWidget

    //获取widget窗口的坐标以及大小
    QRect rect = this->geometry();
    //将Label控件设置成窗口大小
    ui->label->setGeometry(0, 0, rect.width(), rect.height());
    QPixmap pixmap(":/image/angry-2.png");
    ui->label->setPixmap(pixmap);
    // 启动自动拉伸. 此时图片就能够填充满整个窗口了.
    ui->label->setScaledContents(true);

运行结果:

但是,当我们拉伸窗口是,图片并不会随着我们的拉伸而变化,此时我们就会触发resize事件,像resize这样的事件是连续变化的。如果我们想是图片随着我们的拉伸而变化时,我们就可以通过重写widget(父类)的resizeEvent(虚函数)来改变Label大小

    void resizeEvent(QResizeEvent *event);//声明一下resizeEvent

void Widget::resizeEvent(QResizeEvent *event)
{
    //此处的形参 event 是非常有用的, 这里就包含了触发这个 resize 事件这一时刻, 窗口的尺寸的数值.
    //我们可以通过打印来看event的变化
    qDebug() << event->size();
}

通过不断地拉伸就可以获得widget的长宽

那么我们想设置它的拉伸而改变Label的大小就十分简单了

void Widget::resizeEvent(QResizeEvent *event)
{
    //此处的形参 event 是非常有用的, 这里就包含了触发这个 resize 事件这一时刻, 窗口的尺寸的数值.
    //我们可以通过打印来看event的变化
    qDebug() << event->size();
    ui->label->setGeometry(0,0,event->size().width(), event->size().height());
}

运行结果:

10.3.3 QLabel设置自动换行,边距,缩进

通过这样的设置我们能够更加清楚的,看到Label控件。

创建四个Label控件,分别设置他们的对齐方式,自动换行,缩进,边距

    // 在构造函数中, 给这几个 label 设置不同的属性.

    // 设置对齐方式
    ui->label->setText("这是一段文本");
    ui->label->setAlignment(Qt::AlignRight | Qt::AlignTop);

    // 设置自动换行
    ui->label_2->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本");
    ui->label_2->setWordWrap(true);

    // 设置缩进(需要注意的是,缩进是全部缩进)
    ui->label_3->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本");
    ui->label_3->setWordWrap(true);
    ui->label_3->setIndent(50);

    // 设置边距
    ui->label_4->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本");
    ui->label_4->setWordWrap(true);
    ui->label_4->setMargin(50);

运行结果

在设置对齐方式中提供了很多种,我们可以进入它的枚举中进一步了解

    enum AlignmentFlag {
        AlignLeft = 0x0001,
        AlignLeading = AlignLeft,
        AlignRight = 0x0002,
        AlignTrailing = AlignRight,
        AlignHCenter = 0x0004,
        AlignJustify = 0x0008,
        AlignAbsolute = 0x0010,
        AlignHorizontal_Mask = AlignLeft | AlignRight | AlignHCenter | AlignJustify | AlignAbsolute,

        AlignTop = 0x0020,
        AlignBottom = 0x0040,
        AlignVCenter = 0x0080,
        AlignBaseline = 0x0100,
        // Note that 0x100 will clash with Qt::TextSingleLine = 0x100 due to what the comment above
        // this enum declaration states. However, since Qt::AlignBaseline is only used by layouts,
        // it doesn't make sense to pass Qt::AlignBaseline to QPainter::drawText(), so there
        // shouldn't really be any ambiguity between the two overlapping enum values.
        AlignVertical_Mask = AlignTop | AlignBottom | AlignVCenter | AlignBaseline,

        AlignCenter = AlignVCenter | AlignHCenter
    };

下面是对每个枚举值的解释:

  • AlignLeftAlignLeading:左对齐

  • AlignRightAlignTrailing:右对齐

  • AlignHCenter:水平居中对齐

  • AlignJustify:两端对齐

  • AlignAbsolute:绝对对齐

  • AlignHorizontal_Mask:水平对齐掩码,用于表示所有水平对齐方式的组合

  • AlignTop:顶部对齐

  • AlignBottom:底部对齐

  • AlignVCenter:垂直居中对齐

  • AlignBaseline:基线对齐(该值与 Qt::TextSingleLine = 0x100 可能冲突,但由于 AlignBaseline 只用于布局中,不会传递给 QPainter::drawText(),因此不会产生歧义)

  • AlignVertical_Mask:垂直对齐掩码,用于表示所有垂直对齐方式的组合

  • AlignCenter:居中对齐,既包括垂直居中对齐又包括水平居中对齐

这些枚举值可以组合使用,以实现所需的对齐方式。例如,AlignLeft | AlignTop 表示左上对齐,AlignHCenter | AlignVCenter 表示水平和垂直居中对齐。

10.3.4 QLabel设置伙伴

Qt中QLabel中写的文本,是可以指定为"快捷键"(比之QPushButton逊色很多)

在文本中使用 & + 字符的形式来表示快捷键

比如&A => 通过键盘alt + a出发次快捷键

通过绑定伙伴关系就可以听过快捷按钮选中对应的单选按钮/复选按钮了!

    // 设置 label 和 radioButton 伙伴关系
    ui->label->setBuddy(ui->radioButton);
    ui->label_2->setBuddy(ui->radioButton_2);

运行结果:

10.4 QLCDNumber

QLEDNumber控件是一种显示数字的控件,类似与"老式计算器"

*intValue: QLEDNumber显示的数值(int)
*value: QLCDNumber 显示的数字值(double)和 intValue 是联动的.

例如给 value 设为 1.5,intValue 的值就是 2.

另外,设置 value和intValue的方法名字为display ,而不是 setValue 或者setIntValue
*digitCount: 显示几位数字
*mode: 数字显示形式!

QLCDNumber::Dec:十进制模式,显示常规的十进制数字。

QLCDNumber::Hex:十六进制模式,以十六进制格式显示数字。

QLcDNumber::Bin:二进制模式,以二进制格式显示数字

QLcDNumber::oct :八进制模式,以八进制格式显示数字。

注:只有十进制的时候才能显示小数点后的内容

*segmentStyle: 设置显示风格。

QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上。

QLCDNumber::0utline:轮廓显示风格,数字具有清晰的轮廓和阴影效果。

QLCDNumber::Filled:填充显示风格,数字被填充颜色并与背景区分开。

*smallDecimalPoint:设置比较小的 .小数点

创建一个QLCD Number,让它显示从10到0.

    //设置初始值10
    ui->lcdNumber->display(10);

    //想要实现计时功能,在Qt中提供了一个QTime的计时器
    Timer = new QTimer(this);
    // 把 QTimer 的 timeout 信号和咱们自己的槽函数进行连接
    connect(Timer, &QTimer::timeout, this, &Widget::handleTimer);
    // 启动定时器, 参数是触发 timeout 的周期. 单位是 ms
    Timer->start(1000);

void Widget::handleTimer()
{
    // 先拿到 LCDNumber 中的数字
    int value = ui->lcdNumber->intValue();
    if (value <= 0) {
        // 数字减到 0 了, 停止定时器.
        timer->stop();
        return;
    }
    ui->lcdNumber->display(value - 1);
}

运行结果:

如果我们不使用Qt内置的计时器的话,我们能不能自己写一个计时器呢,不妨试一下

    int value = 10;
    ui->lcdNumber->display(value);
        while (true) {
            // 先休眠 1s
            std::this_thread::sleep_for(std::chrono::seconds(1));
            if (value <= 0) {
                break;
            }
            value -= 1;
            ui->lcdNumber->display(value);
        }

当我们写出这样一段函数,运行之后,我们的程序会在十秒后显示出来

还记得我们之前说过的吗,我们在构造函数执行结束后才会进行显示。

那我们能不能写一个线程,使用多线程去实现这么一个操作呢

    std::thread t([this] () {
        int value = this->ui->lcdNumber->intValue();
        while (true) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            if (value <= 0) {
                break;
            }
            value -= 1;
            ui->lcdNumber->display(value);
        }
    });

运行这段代码后,不仅不会显示,还会出现一个:

这是因为在Qt里,界面只能有主线程(main所在的线程)进行维护更新。

对于GUI来说,内部包含了很多的状态,Qt为保证修改界面的过程中,线程安全不会受到影响,所以禁止了其他线程的修改。

对于Qt来说,槽函数默认情况下是由主函数调用的,在槽函数中修改界面是没有任何问题的。

10.5 ProgressBar

*minimum:进度条最小值
*maximum:进度条最大值
*value:进度条当前值
*alignment:文本中进度条的对其方式

Qt::AlignLeft: 左对齐

Qt::AlignRight:右对齐

Qt::AlignCenter:中间对齐

Qt::AlignJustify:两端对齐

*textVisble:进度条数字是否可见
*orientation:进度条的方向是水平还是垂直
*invertAppearance:是否为朝反向增长的进度

*textDirection:文本朝向
*format:展示的数字格式。

%p:表示进度的百分比(0-100)

%v:表示进度的数值(0-100)

%m:剩余时间(毫秒)

%t:总时间(毫秒)

实现进度条岁时间增长(每个100毫秒+1)

    //设置value的值
    ui->progressBar->setValue(0);
    //创建QTimer实例并绑定
    Timer = new QTimer(this);
    connect(Timer, &QTimer::timeout, this, &Widget::handleTimer);
    //启动Timer计时
    Timer->start(100);

void Widget::handleTimer()
{
    //获取progressBar的值
    int value = ui->progressBar->value();
    if(value >= 100)
    {
        Timer->stop();
        return;
    }
    ui->progressBar->setValue(value + 1);
}

运行结果

不知道大家有没有这样玩过,我们只在.cpp中包含QTimer头文件,而没有在.h中包含,程序却依然可以运行,这是为什么呢。

这个是c++的特殊技巧,在编译横向对比中,C/C++语言的编译时间要比其他语言编译时间更久,经过一些大佬们的研究发现是因为#include包含头文件,文本替换所导致的,为了能够优化这一编译时长的问题。在C++中就提供了一个专门包含所有类的"前置声明"头文件。在Qt中同样也适用,

这样虽然减少了一定的损耗,但是在一些大型项目中,并不会因为只使用它做声明而不包含它的头文件,所以并不能很好的解决这些问题,有些大厂中就会从硬件下手。当然在c++20中引入了module(模版)这个概念,但对于#include依然使用。

10.6 QCalendarWidget

*selectDate:当前选中的日期
*minimumDate:最小日期
*maximumDate:最大日期
*firstDayOfWeek:每周的第一天(也就是日历的第一列) 是周几
*gridVisible:是否显示表格的边框
*selectionMode:是否允许选择日期
*navigationBarVisible:日历上方标题是否显示
*horizontalHeaderFormat:日历上方标题显示的日期格式
*verticalHeaderFormat:日历第一列显示的内容格式
*dateEditEnabled:是否允许日期被编辑

QCalendarWidget信号

selectionChanged(const QDate&):当选中的日期发生改变时发出
activated(const QDate&):当双击一个有效的日期或者按下回车键时发出,形参是一个QDate类型,保存了选中的日期
currentPageChanged(int,int):当年份月份改变时发出,形参表示改变后的新年份和月份

界面中创建一个QCalendarWidget和QLabel,当我们点击QCalendarWidget上的时间时,QLabel也随之发生改变

在Qt Designer中创建QCalendarWidget和QLabel两个控件,然后在QCalendarWidget赚到槽

我们可以打印一下看他的值

void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
    qDebug() << date;
}
void Widget::on_calendarWidget_selectionChanged()
{
    QDate date = ui->calendarWidget->selectedDate();
//    qDebug() << date;
    //将date转为string
    ui->label->setText(date.toString());
}

运行结果:

10.7 QLineEdit

10.7.1 QLineEdit的使用

*text:输入框中的文本
*inputMask:输入内容格式约束
*maxLength:最大长度
*frame:是否添加边框
*echonMode:显示方式

QLineEdit::Normal:这是默认值,文本框会显示输入的文本。

QLineEdit::Password:这种情况下,输入的字符会被隐藏,通常用星号(*)或等号(=)代替。

QLineEdit::NoEcho:在这种模式下,文本框不会显示任何输入的字符。

*cursorPosition:光标所在位置
*alignment:文字对齐方式,设置水平和垂直方向的对齐
*dragEnabled:是否允许拖拽
*readOnly:是否是只读(不允许修改)
*placeHolderText:当输入框内容为空的时候,显示什么样的提示信息
*clearButtonEnabled:是否会自动显示出"清除按钮"

核心信号
*void cursorPositionChanged(int old, int new):当鼠标移动时发出此信号,old为先前的位置,new为新的位置
*void editingFinished():当按返回或者回车键时,或者行编辑失去焦点时,发出此信号
*void returnPressed():当返回或回车键按下时发出此信号
如果设置了验证器,必须要验证通过,才能触发
*void selectionChanged():当选中的文本改变时,发出此信号
*void textChanged(const QString &text):当QLineEdit中的文本改变时,发出此信号,text是新的文本,代码对新文本的修改能够触发这个信号
*void textEdited(const QString &text):当QLineEdit中的文本改变时,发出此信号,text是新的文本。代码对文本的修改不能触发此信号

实现,当用户点击提交时,获取注册内容并打印

    //初始化第一个框提示文本"请输入您的电话号码"
    ui->lineEdit_phone->setPlaceholderText(QString("Please enter your telephone number"));
    ui->lineEdit_phone->setClearButtonEnabled(true);
    //手机号码具有固定格式,此处的"0"代表数字
    ui->lineEdit_phone->setInputMask("000-0000-0000");

    //初始第二框文本"请输入账户"
    ui->lineEdit_account->setPlaceholderText(QString("Please enter account"));
    ui->lineEdit_account->setClearButtonEnabled(true);

    //第三,四框输入文本"请输入密码"和"请确认密码"
    ui->lineEdit_password->setPlaceholderText(QString("enter your PIN"));
    ui->lineEdit_affirm_password->setPlaceholderText(QString("Please confirm password"));
    //密码不希望被其他人知晓所以显示设置为密码模式
    ui->lineEdit_password->setEchoMode(QLineEdit::Password);
    ui->lineEdit_affirm_password->setEchoMode(QLineEdit::Password);
    ui->lineEdit_phone->setClearButtonEnabled(true);
    ui->lineEdit_affirm_password->setClearButtonEnabled(true);

void Widget::on_pushButton_clicked()
{
    qDebug() <<"号码"<<ui->lineEdit_phone->text()
            <<"账户"<<ui->lineEdit_account->text()
           <<"密码"<<ui->lineEdit_password->text()
          <<"确认密码"<<ui->lineEdit_affirm_password->text();
}

运行结果

很明显就算我们两次输入的密码,不相同依旧可以提交,这样显然是不合法的。

    //默认禁止点击提交
    ui->pushButton->setEnabled(false);

void Widget::Compare()
{
    const QString& s1 = ui->lineEdit_password->text();
    const QString& s2 = ui->lineEdit_affirm_password->text();
    ui->pushButton->setEnabled(false);
    if (s1.isEmpty() && s2.isEmpty()) {
        ui->label->setText("Password is empty");
        //如果两次输入的密码相等,且所有QLineEdit控件不为空就将"提交"设置为可用
    } else if (s1 == s2 && !(ui->lineEdit_account->text().isEmpty()) && !(ui->lineEdit_phone->text().isEmpty())) {
        ui->label->setText("The passwords are the same");
        ui->pushButton->setEnabled(true);
    } else {
        ui->label->setText("The password is not the same");
    }
}

void Widget::on_lineEdit_password_textEdited(const QString &arg1)
{
    //防止报警告
    (void)arg1;
    Compare();
}


void Widget::on_lineEdit_affirm_password_textEdited(const QString &arg1)
{
     //防止报警告
    (void)arg1;
    Compare();

}

我们还提供了显示按钮,当它按下就显示其密码内容

void Widget::on_radioButton_toggled(bool checked)
{
    if (checked) {
         // true 则是 "显示密码" 状态, 就把输入框的显示模式, 设为 Normal
         ui->lineEdit_password->setEchoMode(QLineEdit::Normal);
         ui->lineEdit_affirm_password->setEchoMode(QLineEdit::Normal);
     } else {
         // false 则是 "隐藏密码" 状态, 就把输入框的显示模式, 设为 Password
         ui->lineEdit_password->setEchoMode(QLineEdit::Password);
         ui->lineEdit_affirm_password->setEchoMode(QLineEdit::Password);
     }
}

在我们刚才提供的判断号码是否合法的情况的其实是不太完整的,因为inputMask功能比较有限,只能进行简单的验证。为了更好的判断用户所输入内容的合法化,大佬们研究出了"正则表达式"

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

概念:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。

正则表达式的作用:

1.验证数据的有效性

2.替换文本内容

3.从字符串中提取子字符串

    //手机号码具有固定格式,此处的"0"代表数字
   // ui->lineEdit_phone->setInputMask("000-0000-0000");

    // 就需要给单行输入框设置验证器. 基于正则表达式来完成验证的~~
        QRegExp regExp("^1\\d{10}$");
        ui->lineEdit_phone->setValidator(new QRegExpValidator(regExp));

"^1\\d{10}$"这是一个简单的正则表达式,这里我们只是生成了一个验证器,验证器怎么使用,还需要我们自己定义

void Widget::on_lineEdit_phone_textEdited(const QString &arg1)
{
    QString text = arg1;
    int pos = 0;
    if(ui->lineEdit_phone->validator()->validate(text, pos) == QValidator::Acceptable)
    {
        ui->pushButton->setEnabled(true);
    }
    else{
        ui->pushButton->setEnabled(false);
    }
}

1.Invalid:表示状态或结果为无效或不可接受。

2.Intermediate:表示状态或结果为中间状态,可能需要进一步处理或者待定。

3.Acceptable:表示状态或结果为可接受或有效。

10.7.2 QLineEdit属性

QTextEdit 是 Qt 框架中用于显示和编辑文本的控件,它具有许多可设置和调整的属性。以下是一些常用的 QTextEdit 属性:

1.文本内容相关属性:

*text:获取或设置编辑框中的文本内容。

*plainText:获取或设置编辑框中的纯文本内容。

*html:获取或设置编辑框中的 HTML 格式文本内容。

2.显示和布局相关属性:

*lineWrapMode:设置文本自动换行的模式。

*lineWrapColumnOrWidth:设置文本换行的宽度或列数。

*tabStopWidth:设置文本编辑框中 Tab 键的停止位宽度。

*wordWrapMode:设置单词自动换行的模式。

3.字体和样式相关属性:

*font:设置或获取文本编辑框中的字体。

*alignment:设置文本的对齐方式(左对齐、右对齐、居中等)。

*textColor:设置文本的颜色。

4.滚动和视图控制属性:

*verticalScrollBarPolicy:设置垂直滚动条的显示策略。

*horizontalScrollBarPolicy:设置水平滚动条的显示策略。

5.输入相关属性:

*readOnly:设置文本编辑框是否只读。

*acceptRichText:设置是否接受富文本格式。

*autoFormatting:设置自动格式化选项(如自动链接检测等)。

6.选择和光标相关属性:

*cursorWidth:设置光标的宽度。

*cursorFlashTime:设置光标闪烁的时间间隔。

*textInteractionFlags:设置文本的交互标志(包括可编辑、可选择等)。

7.撤销和重做相关属性:

*undoRedoEnabled:设置是否启用撤销和重做功能。

8.文本变化和内容选择信号:

*extChanged:文本内容改变时的信号。

*selectionChanged:选择内容改变时的信号。

本篇文章暂时先写到这里,后续会出一篇进阶,我将介绍其他常用控件,以及在Qt中线程和网络相关的问题。

相关推荐
百事老饼干5 分钟前
Java[面试题]-真实面试
java·开发语言·面试
码农客栈12 分钟前
qt QWebSocketServer详解
qt
杨荧43 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰1 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
王俊山IT1 小时前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。1 小时前
c++多线程
java·开发语言
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯1 小时前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue2 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·