QT(超详细从0开始)

目录

1.2 Qt的优点

2.安装Qt

3.创建项目

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

​编辑

5.Qt Designer

6.Qt对象数

7.Qt乱码问题

8.Qt坐标系的认识

9.信号和槽

9.1 connect

9.2 自定义槽函数

9.3 自定义信号

9.4 断开信号链接(disconnect)

9.5.lambda表达式

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

10.1 QWidget

10.1.1 QWidget的enable属性

10.1.2 QWidget的geometry属性

10.1.3 WindowFrame的影响

10.1.4 QWidget的windowTitle属性

10.1.5 QWidget的windowlcon属性

10.1.6 QWidget的WindowOpacity属性

10.1.7 QWidget的cursor属性

10.1.8 QWidget的font属性

10.1.9 QWidget的toolTip属性

10.1.10 QWidget的focusPolicy属性

10.1.11 QWidget的styleSheet属性

10.2 Button按键

10.2.1 QPushButton添加图标

10.2.2 QPushButton添加快捷

10.2.3 QRadioButton的使用

10.2.4 QCheckBox的使用

10.3 QLabel

10.3.1 QLanel文本显示方式

10.3.2 QLanel设置图片

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

10.3.4 QLabel设置伙伴

10.4 QLCDNumber

10.5 ProgressBar

10.6 QCalendarWidget

10.7 QLineEdit

10.7.1 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中线程和网络相关的问题。

  • 38
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值