Qt入门与实践:一文让你开启Qt大门!附实战项目源码

注意:本文不允许转载,谢谢合作

文章目录

1.Qt概述

1.1 什么是Qt

Qt是一个跨平台的 C++图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。

1.2 Qt的发展史

1991年 Qt 最早由奇趣科技开发
1996年 进入商业领域,它也是目前流行的 Linux 桌面环境 KDE 的基础
2008年 奇趣科技被诺基亚公司收购,Qt 称为诺基亚旗下的编程语言
2012年 Qt 又被 Digia 公司收购
2014 年 4 月 跨平台的集成开发环境 Qt Creator3.1.0 发布,同年 5 月 20 日配发了Qt5.3 正式版,至此 Qt 实现了对 iOS、Android、WP 等各平台的全面支持。

当前Qt 最新版本为 5.15.1

1.3 支持的平台

  • Windows – XP、Vista、Win7、Win8、Win2008、Win10
  • Uinux/X11 – Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、 SGI IRIX、FreeBSD、BSD/OS、和其他很多 X11 平台
  • Macintosh – Mac OS X
  • Embedded – 有帧缓冲支持的嵌入式 Linux 平台,Windows CE

1.4 Qt 版本

Qt按照不同的版本发行,分为商业版和开源版

  • 商业版
    为商业软件提供开发,他们提供传统商业软件发行版,并且提供在商业有效期内的免费升级和技术支持服务
  • 开源的 LGPL 版本:
    为了开发自有而设计的开放源码软件,它提供了和商业版本同样的功能,在GNU 通用公共许可下,它是免费的。

1.5 Qt 的下载与安装

1.5.1 下载

参考我的博客:https://blog.csdn.net/u014779536/article/details/104632239

清华大学开源软件镜像站:https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/

image-20201014172830629

Qt 5.15 是 Qt5 最后的LTS,同时 Qt 5.9 LTS 也将于5月31日终止。

Qt 5.15开始,开源版本,无论是不是 LTS,都只能在线安装

Qt5.15安装请参考:https://blog.csdn.net/u014779536/article/details/106788778

1.5.2 安装
  • 准备好安装包

image-20201014192852365

  • 双击打开

image-20201014193203221

  • 登录账号

image-20201014193237566

  • 同意条款

image-20201014193310233

  • 选择安装路径

image-20201014193334459

image-20201014193353241

  • 选择组件

image-20201014193507457

  • 同意条款

image-20201014193530311

  • 继续下一步,进行安装

image-20201014193549363

image-20201014193557614

  • 正在安装(安装大概持续5分钟)

image-20201014193611184

  • 安装完成

image-20201014194802950

image-20201014194856776

1.6 MSVC方式编译环境搭建

参考博客:https://blog.csdn.net/u014779536/article/details/106848863

1.6.1 VS2019安装

我们在这里选择社区版:
https://visualstudio.microsoft.com/zh-hans/vs/

  • 下载软件
    https://blog.csdn.net/zyhse/article/details/105362609
  • 安装配置
    在这里插入图片描述
    我们主要使用它的编译器。
1.6.2 QT5 安装

我们在这里选择 Qt5.14.2:
https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.14/
在这里插入图片描述
在这里插入图片描述
直接下一步,下一步装完就行,没什么可说的。

1.6.3 MSVC调试器安装

通过windows SDK工具安装调试器:
https://developer.microsoft.com/zh-cn/windows/downloads/windows-10-sdk/
安装程序下载
在这里插入图片描述
安装过程
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.6.4 Qt Creator配置编译器和调试器
  • 打开 工具-> 选项
    在这里插入图片描述
  • 配置 Debuggers
    这里系统会自动检测到,不用选择,如果没有检测到,请重新按照第3节安装。
    在这里插入图片描述
  • 配置编译器
    这里也会自动检测到,如果没有,请重新按照第1节进行安装。
    在这里插入图片描述
  • 配置Qt 5.14.2 MSVC2017 32bit
    在这里插入图片描述
  • 配置Qt 5.14.2 MSVC2017 64bit
    在这里插入图片描述
1.6.5 配置完成,进行测试
  • 文件编码格式要为UTF-8-BOM
    在这里插入图片描述
  • 配置断点
    在这里插入图片描述
  • 执行调试模式
    在这里插入图片描述

2.创建Qt项目

2.1 使用向导创建

image-20201014195236229

image-20201014195259339

  • 设置工程名和路径

image-20201014195347667

  • 选择qmake

image-20201014195425514

  • 设置主界面类及ui文件名称,默认即可

image-20201014195523027

  • 多语言,默认即可

image-20201014195722502

  • 选择编译方式

image-20201014195904131

  • 添加版本控制

image-20201014195938372

  • 完成创建,自动生成工程

image-20201014200035431

2.2 .pro文件

在使用 Qt 向导生成的应用程序.pro 文件格式如下:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

.pro 就是工程文件(project),它是 qmake 自动生成的用于生产 makefile 的配置文件。.pro 文件的写法如下:

  • 注释

    从“#”开始,到这一行结束。

  • 指定生成的应用程序名:
    TARGET = QtDemo

  • 工程中包含的头文件
    HEADERS += include/painter.h

  • 工程中包含的.ui 设计文件
    **FORMS ** += forms/painter.ui

  • 工程中包含的源文件
    SOURCES += sources/main.cpp sources

  • 工程中包含的资源文件
    RESOURCES += qrc/painter.qrc

  • greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    这条语句的含义是,如果QT_MAJOR_VERSION大于4(也就是当前使用的Qt5及更高版本)需要增加widgets模块。如果项目仅需支持Qt5,也可以直接添加“QT += widgets”一句。不过为了保持代码兼容,最好还是按照QtCreator生成的语句编写。

  • 配置信息
    CONFIG 用来告诉 qmake 关于应用程序的配置信息。
    CONFIG += c++11 //使用 c++11 的特性

在这里使用“+=”,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“=”那样替换已经指定的所有选项更安全。

2.3 一个最简单的Qt应用程序

main入口函数中 :

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

解释:

  • Qt 系统提供的标准类名声明头文件没有.h 后缀
  • Qt 一个类对应一个头文件,类名就是头文件名
  • QApplication 应用程序类
    • 管理图形用户界面应用程序的控制流和主要设置。
    • 是 Qt 的整个后台管理的命脉它包含主事件循环,在其中来自窗口系统和其它资源的****所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理
    • 对于任何一个使用 Qt 的图形用户界面应用程序,都正好存在一个QApplication 对象,而不论这个应用程序在同一时间内是不是有 0、1、 2 或更多个窗口。
  • a.exec()
    程序进入消息循环,等待对用户输入进行响应。这里 main()把控制权转交给Qt,Qt 完成事件处理工作,当应用程序退出的时候 exec()的值就会返回。在 exec()中,Qt 接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

3.第一个Qt小程序

3.1 运行一下默认生成的程序

  • 点击运行按钮,或者按Ctrl+B

image-20201014201243879

  • 什么也没有

image-20201014201307362

3.2 添加两个按钮(使用代码添加

  • 我们首先来到主窗口的构造函数

    image-20201015082012435

    添加以下代码:

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //头文件 #include <QPushButton>
        QPushButton * btn = new QPushButton;
        btn->resize(100,20);
        //设置父亲
        btn->setParent(this);
        //设置文字
        btn->setText("德玛西亚");
        //移动位置
        btn->move(100,100);
        //第二种创建
        QPushButton * btn2 = new QPushButton("孙悟空",this);
        btn2->resize(100,20);
        //重新指定窗口大小
        this->resize(600,400);
        //设置窗口标题
        this->setWindowTitle("第一个项目");
        //限制窗口大小
        this->setFixedSize(600,400);
    }
    

    image-20201015082418087

  • 运行代码,查看效果

    image-20201015082640885

大家有没有觉得这样添加控件太麻烦了?别着急,我们先来看一下Qt窗口坐标体系

3.3 Qt窗口坐标体系

坐标体系:
以左上角为原点(0,0),X 向右增加,Y 向下增加。

image-20201015085817450

对于嵌套窗口,其坐标是相对于父窗口来说的。

3.4 以可视化方式创建两个按钮

根据3.2节来创建我们的界面真的是太麻烦了!我们有没有更好的方式呢?

有的!Qt 为我们提供了界面可视化创建工具:Qt Designer

image-20201015090127032

这么多?我们该选哪一个呢?

使用Qt Creator开发的话就不用选择,系统内直接打开。其他情况就根据您所选的编译方式来决定选用哪个版本。

等不及了,让我们开始吧~

3.4.1 在Creator内打开界面设计器

image-20201015090519828

  • 自动跳转到设计界面

    image-20201015090658620

3.4.2 在窗口添加两个按钮
  • 拖动,拖动,拖动,这次我们直接拖动控件到窗口区

    image-20201015090905032

  • 我们可以对按钮进行属性设置,这里,我们就改一个名字

    双击即可更改内容,此处我们改为按钮1,按照同样的方法添加按钮2

    image-20201015091247230

  • 运行,试试效果

    image-20201015091340601

  • 这里我们先把通过代码添加按钮的代码删除,进行下一个环节

    image-20201015091457849

    image-20201015091530316

3.4.3 点击按钮生成Qt版本的Hello World

我们刚才已经成功创建了按钮,但是我们点击按钮却没有任何反应。

这是为什么呢?

因为我们只是添加了按钮,却没有让它做任何事情,那么,它肯定不会有任何动作啦~

接下来先跟着操作一遍,具体原理第4节就会进行说明。

  • 双击打开mainwindow.ui界面文件

    image-20201015092336390

  • 使用鼠标右键单击按钮1

    弹出菜单,点击转到槽:

    image-20201015092556961

  • 转到槽窗口

    image-20201015092641835

  • 选择clicked(),表示单击信号,点击ok

    image-20201015092803056

  • 接下来在界面顶端添加QDebug头文件

    image-20201015092915237

    #include <QDebug>
    
  • 然后在向刚才按钮生成的槽函数中添加以下打印代码

    image-20201015093042235

    void MainWindow::on_pushButton_clicked()
    {
        qDebug() << "Hello Qt!";
    }
    
  • 运行程序,单击按钮1

    image-20201015093200440

    image-20201015093257663

4.信号和槽机制

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

4.1 系统自带的信号和槽

下面我们完成一个小功能,上面我们已经学习了按钮的创建,按钮最大的功能也就是点击后触发一些事情,比如我们点击按钮,就把当前的窗口给关闭掉,那么在Qt 中,这样的功能如何实现呢?

其实两行代码就可以搞定了,我们看下面的代码:

image-20201015094439499

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    // 新建一个按钮,并关联窗口关闭槽函数(系统自带)
    QPushButton * quitBtn = new QPushButton("关闭窗口",this);   
    connect(quitBtn,&QPushButton::clicked,this,&MainWindow::close); 
}
  • 运行程序查看效果

    image-20201015094650005

    单击一下,窗口会关闭

第一行是创建一个关闭按钮,这个之前已经学过,第二行就是核心了,也就是信号槽的使用方式 。

同样,我们也可以在使用界面创建的按钮槽函数使用系统自带槽函数:

image-20201015094824883

void MainWindow::on_pushButton_clicked()
{
    qDebug() << "Hello Qt!";
    this->close();
}

image-20201015094935541

接下来我们继续说槽函数,connect()函数最常用的一般形式:

connect(sender, signal, receiver, slot); 

参数说明:

  • sender:发出信号的对象
  • signal:发送对象发出的信号
  • receiver:接收信号的对象
  • slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

那么系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入 QPushButton,首先我们可以在 Contents 中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton 中就可以找到该关键字,点击 signals 索引到系统自带的信号有如下几个

image-20201015095224740

image-20201015095355669

  • 找到他的父类

    image-20201015095504597

  • 查看父类的子类

    image-20201015095549018

  • 往下滑动,查看信号

    image-20201015095838002

这里的clicked 就是我们要找到,槽函数的寻找方式和信号一样,只不过他的关键字是 slot。

  • 查看槽函数

    image-20201015100002458

4.2 自定义信号和槽

使用 connect()可以让我们连接系统提供的信号和槽。但是,Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。 下面我们看看使用 Qt 的信号槽:

  • mainwindow.h中添加如下代码

    image-20201015101108478

  • 右键单击,为槽函数快速添加定义

    image-20201015101156135

  • 为槽函数添加代码

    引入头文件

    #include <QMessageBox>
    

    image-20201015101400094

    void MainWindow::slot_eat()
    {
        QMessageBox::information(this,"标题","自定义槽函数");
    }
    
  • 在构造函数中关联信号与槽

    image-20201015101729602

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // 新建一个按钮,并关联窗口关闭槽函数(系统自带)
        QPushButton * quitBtn = new QPushButton("关闭窗口",this);
        connect(quitBtn,&QPushButton::clicked,this,&MainWindow::close);
        
        // 关联自定义信号与槽
        connect(this,&MainWindow::signals_hungury,this,&MainWindow::slot_eat);
    }
    
  • 在按钮中使用该信号

    image-20201015101526100

    其中,emit表示要发出信号了:

    void MainWindow::on_pushButton_clicked()
    {
        qDebug() << "Hello Qt!";
    //    this->close();
        emit this->signals_hungury();
    }
    
  • 运行查看效果

    image-20201015101812685

**自定义信号槽需要注意的事项: **

  • 发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda表达式等无需接收者的时候除外);
  • 信号和槽函数返回值是 void
  • 信号只需要声明,不需要实现
  • 槽函数需要声明也需要实现
  • 槽函数是普通的成员函数,作为成员函数,会受到 public、private、 protected 的影响;
  • 使用 emit 在恰当的位置发送信号;
  • 使用connect()函数连接信号和槽。
  • 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
  • 信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
  • 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。

4.3 信号槽的拓展

  • 一个信号可以和多个槽相连
    如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
  • 多个信号可以连接到一个槽
    只要任意一个信号发出,这个槽就会被调用。
  • 一个信号可以连接到另外的一个信号
    当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
  • 槽可以被取消链接
    这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。
  • 信号槽可以断开
    利用disconnect 关键字是可以断开信号槽的
  • 使用 Lambda 表达式
    在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。 在连接信号和槽的时候,槽函数可以使用 Lambda 表达式的方式进行处理。

后面我们会详细介绍什么是 Lambda 表达式 。

4.4 Qt4 版本的信号槽写法

connect(this,SIGNAL(signals_hungury()),this,SLOT(slot_eat()));

这里使用了 SIGNAL 和 SLOT 这两个宏,将两个函数名转换成了字符串。注意到connect()函数的 signal 和 slot 都是接受字符串,一旦出现连接不成功的情况,Qt4 是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。
Qt5 在语法上完全兼容 Qt4,而反之是不可以的。

4.5 Lambda 表达式

C++11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda 表达式的基本构成:

//[函数对象参数](操作符重载函数参数)mutable ->返回值{函数体} 
[capture](parameters) mutable -> return-type
{ 
	statement 
} 

① 函数对象参数;

[],标识一个 Lambda 的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括Lambda 所在类的 this)。函数对象参数有以下形式:

  • 空 |没有使用任何函数对象参数。
  • = |函数体内可以使用 Lambda 所在作用范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
  • & |函数体内可以使用 Lambda 所在作用范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
  • this |函数体内可以使用 Lambda 所在类中的成员变量。
  • a |将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的a 的拷贝,因为默认情况下函数是 const 的。要修改传递进来的 a 的拷贝,可以添加 mutable修饰符。
  • &a |将 a 按引用进行传递。
  • a, &b |将 a 按值进行传递,b 按引用进行传递。
  • =,&a, &b |除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
  • &, a, b |除 a 和 b 按值进行传递外,其他参数都按引用进行传递。

② 操作符重载函数参数;
标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

③ 可修改标示符;
mutable 声明,这部分可以省略。按值传递函数对象参数时,加上 mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。

    QPushButton * myBtn = new QPushButton (this); 
    QPushButton * myBtn2 = new QPushButton (this); 
    myBtn2->move(100,100); 
   int m = 10; 
    connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; }); 
    connect(myBtn2,&QPushButton::clicked,this,[=] ()  { qDebug() << m; }); 
    qDebug() << m; 

④ 函数返回值;
->返回值类型,标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

⑤ 是函数体;
{},标识函数的实现,这部分不能省略,但函数体可以为空。

5.常用控件

Qt 为我们应用程序界面开发提供的一系列的控件,下面介绍几种最常用的控件,所有控件的使用方法我们都可以通过帮助文档获取。

5.1 标签:QLabel

QLabel 是我们最常用的控件之一,其功能很强大,我们可以用来显示文本,图片和动画等。

image-20201015104409941

5.1.1 显示文字(普通文本、html)

通过QLabel 类的 setText 函数设置显示的内容:

void setText(const QString &); 
  • 可以显示普通文本字符串

    QLable *label = new QLable(); 
    label->setText(“Hello, World!); 
    
  • 可以显示 HTML 格式的字符串

    比如显示一个链接:

    QLabel * label = new QLabel(this); 
    label ->setText("Hello, World"); 
    label ->setText("<h1><a href=\"https://www.baidu.com\">百度一下</a></h1>"); 
    label ->setOpenExternalLinks(true); 
    

    其中 setOpenExternalLinks()函数是用来设置用户点击链接之后是否自动打开链接,如果参数指定为 true 则会自动打开。

5.1.2 显示图片

可以使用QLabel 的成员函数 setPixmap 设置图片

void setPixmap(const QPixmap &);

首先定义QPixmap 对象

QPixmap pixmap; 

然后加载图片

pixmap.load(":/Image/boat.jpg"); 

最后将图片设置到 QLabel 中

QLabel *label = new QLabel; label.setPixmap(pixmap); 
5.1.3 显示动画

可以使用QLabel 的成员函数 setMovie 加载动画,可以播放 gif 格式的文件

void setMovie(QMovie * movie);

首先定义QMovied 对象,并初始化:

QMovie *movie = new QMovie(":/Mario.gif");

播放加载的动画:

movie->start(); 

将动画设置到QLabel 中:

QLabel *label = new QLabel;
label->setMovie(movie); 

5.2 输入框:QLineEdit

image-20201015104438465

5.2.1 设置/获取内容
  • 获取编辑框内容使用 text(),函数声明如下:

    QString text() const;
    
  • 设置编辑框内容

    void setText(const QString &);
    
5.2.2 设置显示模式

使用QLineEdit 类的 setEchoMode () 函数设置文本的显示模式,函数声明:

void setEchoMode(EchoMode mode);

EchoMode是一个枚举类型,一共定义了四种显示模式:

  • QLineEdit::Normal 模式显示方式,按照输入的内容显示。
  • QLineEdit::NoEcho 不显示任何内容,此模式下无法看到用户的输入。
  • QLineEdit::Password 密码模式,输入的字符会根据平台转换为特殊字符。
  • QLineEdit::PasswordEchoOnEdit 编辑时显示字符否则显示字符作为密码。

另外,我们再使用 QLineEdit 显示文本的时候,希望在左侧留出一段空白的区域,那么,就可以使用 QLineEdit 给我们提供的 setTextMargins 函数:

void setTextMargins(int left, int top, int right, int bottom);

用此函数可以指定显示的文本与输入框上下左右边界的间隔的像素数。

5.3 按钮:QPushButton

image-20201015104509998

我们通过帮助手册学习QPushButton:

image-20201015110433940

帮助目录:

image-20201015110751238

image-20201015111247143

5.3.1 QPushButton Properties 属性

image-20201015111422722

  • autoDefault : bool

image-20201015111458876

此属性保存按钮是否为自动默认按钮。

如果此属性设置为true,则按钮为自动默认按钮。

在某些GUI样式中,将绘制一个默认按钮,并在其周围有一个额外的框,最多3个像素或更多。 Qt会自动在自动默认按钮周围保留此空间,即自动默认按钮的提示可能会稍大。

对于具有QDialog父级的按钮,此属性的默认值为true;否则为false。 否则默认为false。

有关默认和自动默认如何交互的详细信息,请参见default属性。

Access functions(访问函数):

boolautoDefault() const
voidsetAutoDefault(bool)
  • default : bool

image-20201015111658793

此属性保存按钮是否为默认按钮

Default和autodefault按钮决定当用户在对话框中按Enter键时发生的情况。

当用户按下Enter键时,具有此属性设置为true的按钮(即对话框的默认按钮)将自动被按下,但有一个例外:如果autoDefault按钮当前具有焦点,则按下autoDefault按钮。 当对话框具有autoDefault按钮但没有默认按钮时,按Enter键将按当前具有焦点的autoDefault按钮,或者如果没有按钮具有焦点,则按焦点链中的下一个autoDefault按钮。

在对话框中,一次只能有一个按钮是默认按钮。 然后,此按钮会显示一个额外的框架(取决于GUI样式)。

默认按钮行为仅在对话框中提供。 当按钮具有焦点时,始终可以通过按空格键从键盘上单击按钮。

如果在对话框可见时将当前默认按钮的default属性设置为false,则下次对话框中的按钮获得焦点时,将自动分配一个新的默认值。

此属性的默认值为false。

Access functions:

boolisDefault() const
voidsetDefault(bool)
  • flat : bool

image-20201015111839370

此属性保持按钮边框是否被弹出。

此属性的默认值为false。 如果设置了此属性,除非按下按钮,否则大多数样式都不会绘制按钮背景。 setAutoFillBackground()可用于确保使用QPalette :: Button画笔填充背景。

Access functions:

boolisFlat() const
voidsetFlat(bool)
5.3.2 QPushButton Public Functions 公共方法

image-20201015112337093

  • 构造函数:根据icon,文字和父类来生成按钮

    QPushButton::QPushButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr)
    Constructs a push button with an icon and a text, and a parent.
    Note that you can also pass a QPixmap object as an icon (thanks to the implicit type conversion provided by C++).
    
  • 构造函数:根据文字和父类来生成按钮

    QPushButton::QPushButton(const QString &text, QWidget *parent = nullptr)
    Constructs a push button with the parent parent and the text text.
    
  • 构造函数:生成默认属性按钮

    QPushButton::QPushButton(QWidget *parent = nullptr)
    Constructs a push button with no text and a parent.
    
  • 析构函数:销毁按钮

    [virtual] QPushButton::~QPushButton()
    Destroys the push button.
    
  • 设置关联菜单

    void QPushButton::setMenu(QMenu *menu)
    

    image-20201015113120444

    将弹出菜单菜单与此按钮关联。 这会将按钮变成菜单按钮,在某些样式中,该按钮将在按钮文本的右侧产生一个小三角形。

    菜单的所有权未转移到按钮。

5.3.3 QPushButton Reimplemented Public Functions 经过重载的公共方法

image-20201015141828350

参考博客:https://blog.csdn.net/wukai_std/article/details/54600185

  • 最小尺寸

    [override virtual] QSize QPushButton::minimumSizeHint() const
    Reimplements an access function for property: QWidget::minimumSizeHint.
    
    • image-20201015142009928

    该属性保存建议的窗口小部件最小尺寸。

    如果此属性的值是无效尺寸,则不建议使用最小尺寸。

    如果没有此小部件的布局,minimumSizeHint()的默认实现将返回无效的大小,否则,将返回布局的最小大小。 大多数内置窗口小部件会重新实现minimumSizeHint()。

    除非设置了minimumSize()或将大小策略设置为QSizePolicy :: Ignore,否则QLayout绝不会将窗口小部件的大小调整为小于最小大小提示。 如果设置了minimumSize(),则最小尺寸提示将被忽略。

  • sizeHint() 返回 layout的首选尺寸

    [override virtual] QSize QPushButton::sizeHint() const
    Reimplements an access function for property: QWidget::sizeHint. 
    
    • image-20201015142105344

    此属性保存小部件的建议大小。

    如果此属性的值是无效大小,则不建议使用任何大小。

    如果此小部件没有布局,则sizeHint()的默认实现将返回无效的大小,否则,将返回布局的首选大小。

5.3.4 QPushButton Public Slots 公共槽函数

image-20201015142545916

[slot] void QPushButton::showMenu()
Shows (pops up) the associated popup menu. If there is no such menu, this function does nothing. This function does not return until the popup menu has been closed by the user.

显示(弹出)相关的弹出菜单。 如果没有这样的菜单,则此功能不起作用。 直到用户关闭了弹出菜单,此功能才返回。

5.3.5 QPushButton Protected Functions 保护函数

image-20201015142656506

[protected] void QPushButton::initStyleOption(QStyleOptionButton *option) const
Initialize option with the values from this QPushButton. This method is useful for subclasses when they need a QStyleOptionButton, but don't want to fill in all the information themselves.
See also QStyleOption::initFrom().

使用此QPushButton中的值初始化选项。 当子类需要QStyleOptionButton但又不想自己填写所有信息时,此方法很有用。

5.3.6 QPushButton Reimplemented Protected Functions 经过重载的保护函数

image-20201015142822805

[override virtual protected] bool QPushButton::event(QEvent *e)
Reimplements: QAbstractButton::event(QEvent *e).
    
[override virtual protected] void QPushButton::focusInEvent(QFocusEvent *e)
Reimplements: QAbstractButton::focusInEvent(QFocusEvent *e).
    
[override virtual protected] void QPushButton::focusOutEvent(QFocusEvent *e)
Reimplements: QAbstractButton::focusOutEvent(QFocusEvent *e).
    
[protected] void QPushButton::initStyleOption(QStyleOptionButton *option) const
Initialize option with the values from this QPushButton. This method is useful for subclasses when they need a QStyleOptionButton, but don't want to fill in all the information themselves.
    
See also QStyleOption::initFrom().
    
[override virtual protected] void QPushButton::keyPressEvent(QKeyEvent *e)
Reimplements: QAbstractButton::keyPressEvent(QKeyEvent *e).
5.3.7 QPushButton Detailed Description 细节说明

image-20201015142937383

更多详情,见参考文档

6.实战项目:点名程序

软件详情:

点名系统

接下来我们做一个简化版的,就是去掉所有样式,只关注核心功能:

6.1 新建工程

image-20201015143634787

  • 取名叫CallNames_System

image-20201015143744982

  • 一直下一步,直到选择MinGW编译器

image-20201015143839423

  • 创建成功

image-20201015143935180

6.2 设计界面

  • 我们先来看一下系统构成

    image-20201015144209738

  • 我们这里实现主要的1,4,5,6就可以了

    image-20201015144320707

  • 双击打开界面ui文件

    image-20201015144414421

  • 拖动并放入标签和按钮,效果如下

    image-20201015144607272

  • 运行一下,程序效果如下:

    image-20201015144721057

6.3 使用设计器设置控件属性

我们从6.2节中看到,运行程序后,界面显示字体不是我们想要的效果,我们需要对其进行修改

6.3.1 修改窗口名称

image-20201015145021321

  • 修改完成

    image-20201015145054158

  • 运行显示

image-20201015145130850

  • 还可以设置图标

    image-20201015145152265

6.3.2 修改姓名滚动标签字体和大小

image-20201015145240087

  • 修改标签显示内容为滚动标签

image-20201015145322293

  • 修改其字体为微软雅黑,粗体,48号字体

    image-20201015145449522

  • 居中对齐

image-20201015145525503

  • 修改objectNamelabel_rollNames,程序中会使用此名称

    image-20201015145640385

  • 运行程序:

image-20201015145750343

6.3.3 修改复位,开始,停止按钮
  • 复位按钮

image-20201015145949276

image-20201015150024008

image-20201015150054910

  • 开始按钮

image-20201015150149442

image-20201015150135687

image-20201015150207211

  • 停止按钮

image-20201015150226446

image-20201015150236837

image-20201015150248472

运行程序:

image-20201015150329774

6.3.4 修改信息提示标签字体,大小
  • 修改标签大小

image-20201015150432557

  • 修改文字对齐方式,字体,字体大小

image-20201015150535709

image-20201015150605761

  • 修改字体颜色

image-20201015150637625

  • 修改标签名

    image-20201015150757085

  • 运行程序:

    image-20201015150717645

6.3.5 界面对象名称总结

至此,抽奖程序的主界面已经设计完成。每个控件都有自己的对象名称,我们将在程序中使用其对象名称对其进行操作,让我们再次回顾一下对象名称:

  • 滚动标签:label_rollNames
  • 复位按钮:pushButton_reset
  • 开始按钮:pushButton_start
  • 停止按钮:pushButton_stop
  • 信息提示标签:label_message

6.4 依次给每个按钮添加槽函数

image-20201015151331889

image-20201015151449384

添加测试代码,测试槽函数是否添加成功:

  • 引入QDebug头文件

    #include <QDebug>
    
  • 给复位按钮添加测试代码

    void MainWindow::on_pushButton_reset_clicked()
    {
        qDebug() << "我按下了复位按钮!";
    }
    
  • 给开始按钮添加测试代码

    void MainWindow::on_pushButton_start_clicked()
    {
        qDebug() << "我按下了开始按钮!";
    }
    
  • 给停止按钮添加测试代码

    void MainWindow::on_pushButton_stop_clicked()
    {
        qDebug() << "我按下了停止按钮!";
    }
    

执行程序,观察效果:

  • 按下复位按钮

image-20201015151832262

  • 按下开始按钮

    image-20201015151907128

  • 按下停止按钮

    image-20201015151927998

按下按钮,改变标签文字:

image-20201015152140425

image-20201015152205600

至此,我们已经完成了操作点名程序控件的所有操作学习!

将代码恢复成以下样子,删除标签控制语句:

void MainWindow::on_pushButton_reset_clicked()
{
    qDebug() << "我按下了复位按钮!";
}

void MainWindow::on_pushButton_start_clicked()
{
    qDebug() << "我按下了开始按钮!";
}

void MainWindow::on_pushButton_stop_clicked()
{
    qDebug() << "我按下了停止按钮!";
}

6.5 思考点名程序功能

核心功能:

  • 实现随机点名,用户可以通过点击复位、开始、停止程序来随机点名。

功能拆解:

  • 加载名字列表
  • 随机获取名字
  • 开始标签滚动
  • 停止标签滚动
  • 复位按钮功能

6.6 程序实现

6.6.1 初始化名字列表

这里,我们使用QVector来保存名字。

  • 在mainwindow.h中定义名字列表变量

    QVector<QString> allNameList;
    

    image-20201015153324858

  • 初始化,姓名列表,向里面增加姓名

image-20201015153442788

image-20201015153517104

  • 添加函数体

image-20201015154044363

void MainWindow::initNameList()
{
    // 清空该容器
    this->allNameList.clear();
    
    // 向容器中新增名字
    this->allNameList.append(QString("张三"));
    this->allNameList.append(QString("李四"));
    this->allNameList.append(QString("王五"));
    this->allNameList.append(QString("王二麻子"));
    this->allNameList.append(QString("孙悟空"));
    this->allNameList.append(QString("猪八戒"));
    this->allNameList.append(QString("奥特曼"));
    this->allNameList.append(QString("张飞"));
    this->allNameList.append(QString("武松"));
    
    // 打印一下
    qDebug() << "allNameList:"<<allNameList;
    qDebug() << "姓名列表长度为:" << allNameList.length();
}
  • 在复位按键槽函数中调用姓名初始化函数

image-20201015154108566

测试成功:

image-20201015154129540

此处,姓名也可以从文件中读取,这里为了演示简单,直接定义

6.6.2 随机获取名字

这里,先介绍一个获取随机数的函数:

在Qt中,生成随机数的函数为 qrand()。该函数是标准C++函数 rand 的线程安全版本。不过,如果我们仅仅只是调用该函数来生成随机数,那么每次得到的随机数都将是相同的,这是因为Qt生成的随机数严格来说是一个“伪随机”,它的产生是根据随机数种子计算得到的。如果种子相同,那么所得到的随机数也是相同的。

因此,为了使我们的随机数看起来更为“随机”一些,我们在每次获取随机数之前都需要初始化一个不同的随机数种子,这就需要用到qsrand()函数,该函数只有一个整型参数,即要设置的随机数种子。

函数原型:

void qsrand(uint seed);

int qrand();

例子:

void Widget::on_pushButton_clicked()
{
    //在这个示例里,每次点击按钮就在标签显示一个随机数
    QTime time;
    time= QTime::currentTime();
    qsrand(time.msec()+time.second()*1000);
    int rand = qrand() % 10;                                    //产生十以内的随机数(0-9)
    ui->label->setText(tr("产生的随机数:%1").arg(rand));
 
}
  • 根据随机数来随机获取名字

image-20201015154421417

  • 添加实现

    引入头文件

    #include <QTime>
    

    函数定义如下:

    image-20201015155618840

    QString MainWindow::getRandomName()
    {
        // 获取姓名列表长度
        int nameLength = this->allNameList.length();
    
        // 根据时间来设置种子,保证真随机
        QTime time = QTime::currentTime();
        qsrand(time.msec()+time.second()*1000);   //设置随机数种子
        int rand = qrand() % nameLength;          //产生名字总数内的随机数
    
        // 取得名字
        QString randomName = this->allNameList[rand];
    
        // 返回名字
        return randomName;
    }
    
  • 我们将此函数添加到开始按钮槽函数内进行测试

image-20201015155342773

void MainWindow::on_pushButton_start_clicked()
{
    qDebug() << "我按下了开始按钮!";
    QString name = this->getRandomName();
    ui->label_rollNames->setText(name);
}

使用前记得复位,不然名称列表里面没名字

6.6.3 开始标签滚动

标签通过什么方式就可以滚动了呢?

滚动,其实也就是定时切换,我们需要用到定时器

  • 在头文件中添加定时器声明

    引入头文件:#include <QTimer>

    image-20201015161220280

    添加定时器结束槽函数定义:

    image-20201015161447609

    void MainWindow::rollTimerTimeOut()
    {
        // 随机获取名字
        QString name = this->getRandomName();
        // 设置滚动标签为随机获取到的名字
        ui->label_rollNames->setText(name);
    }
    

    定义定时器对象,并关联槽函数:

    image-20201015161633701

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // 系统启动时进行复位
        this->on_pushButton_reset_clicked();
    
        // 关联定时器定时到信号与槽函数
        this->rollTimer = new QTimer(this);
        connect(rollTimer,&QTimer::timeout,this,&MainWindow::rollTimerTimeOut);
    }
    
  • 运行程序

    image-20201015161755448

并没有滚动,为什么呢?

原来啊,是我们没有启动定时器,我们在开始按钮槽函数里面启动定时器

image-20201015161915533

void MainWindow::on_pushButton_start_clicked()
{
    qDebug() << "我按下了开始按钮!";
    
    if (rollTimer->isActive()==false)
    {
       rollTimer->start(50);
    }
}

再次运行,点击开始,就开始滚动了。

但是怎么停止呢?我们接下来实现停止功能

6.6.4 停止标签滚动

image-20201015162212118

void MainWindow::on_pushButton_stop_clicked()
{
    qDebug() << "我按下了停止按钮!";
    
    // 停止定时器
    if (rollTimer->isActive()==true)
    {
       rollTimer->stop();
    }

    // 获取当前姓名滚动标签内的名字
    QString currentName = ui->label_rollNames->text();
    
    // 生成提示语句
    QString showMessage = "恭喜 " + currentName + "!!";
    // 显示提示信息
    ui->label_message->setText(showMessage);
}

运行程序:

image-20201015162304956

6.6.5 复位按钮功能

image-20201015162942283

void MainWindow::on_pushButton_reset_clicked()
{
    qDebug() << "我按下了复位按钮!";
    this->initNameList();
    ui->label_rollNames->setText("等待开始");
    ui->label_message->setText("幸运儿是你吗?");
    ui->label_message->setStyleSheet("color: red");
}

6.7 程序演示

image-20201015163014871

image-20201015163028986

7.Qt程序打包

现在程序开发完成了,我们怎么打包给其他用户进行使用呢?

  • 目前我们都是使用的Debug版本,为了发布,我们使用Release版本进行编译

image-20201015163241544

​ 运行一次

image-20201015163323668

  • 来到工程路径

image-20201015163135272

  • 返回上一级,进入Release文件夹

image-20201015163356607

image-20201015163407139

  • 从开始菜单找到命令行工具,注意与自己的编译方式一致!!

image-20201015163512128

  • 进入刚才Release程序路径

image-20201015163606644

  • 执行命令
windeployqt CallNames_System.exe

image-20201015163717879

image-20201015163805922

image-20201015163829291

  • 将本路径内容全部压缩到一个压缩包,发给其它人即可使用!

image-20201015163927994

image-20201015163946219

至此,将压缩包发送给其它人即可使用!

image-20201015164015101

感谢大家!!!

已标记关键词 清除标记
<p> <br /> </p> <p> <span style="font-size:9pt;"><span>    </span></span><span style="font-size:9pt;"><span style="font-size:16px;">本课程系统地介绍嵌入式</span><span style="font-size:16px;">GUI</span><span style="font-size:16px;">开发。通过本课程的学习,可以掌握跨平台</span><span style="font-size:16px;">QT</span><span style="font-size:16px;">的环境搭建和移植,掌握</span><span style="font-size:16px;">Linux</span><span style="font-size:16px;">下</span><span style="font-size:16px;">GUI</span><span style="font-size:16px;">的开发方法,为产品开发打下坚实的基础。使学员能熟悉</span><span style="font-size:16px;">Qt/Embedded</span><span style="font-size:16px;">编程方法和编程技能、熟悉</span><span style="font-size:16px;">Qt</span><span style="font-size:16px;">的编程风格、常用的基础类;熟悉</span><span style="font-size:16px;">Qt</span><span style="font-size:16px;">的信号和槽的概念和对象间通讯机制、</span><span style="font-size:16px;">Qt</span><span style="font-size:16px;">的核心事件机制(</span><span style="font-size:16px;">QT</span><span style="font-size:16px;">的驱动核心)、熟练使用</span><span style="font-size:16px;">designer</span><span style="font-size:16px;">编写图形界面;同时熟悉</span><span style="font-size:16px;">Qt</span><span style="font-size:16px;">的网络编程技巧与</span><span style="font-size:16px;">Qt</span><span style="font-size:16px;">的数据库编程。</span><span></span></span> </p> <p> <span style="font-size:16px;">   课程项目案例:</span> </p> <p> <span style="font-size:16px;">   1. 计算机模拟程序开发</span> </p> <p> <span style="font-size:16px;">   2. 记事本小程序</span> </p> <p> <span style="font-size:16px;">   3. FTP客户端程序</span> </p> <p> <span style="font-size:16px;">   4. 智能手机通讯录程序</span> </p>
相关推荐
<p> <span>要想成为高级程序员,<span>必须精通</span>C++。大量第三方开源库使用C++编写。开发移动应用的一些核心功能必须使用C C++。Qt是大公司大量使用的跨平台c++库,号称工具软件之王。Qt作为一个如此高效,跨平台的GUI开发框架,如何快速掌握其精髓?写出高质量,复杂的交互?这是困扰很多中高级开发人员,很头疼的一个问题。在这个课程中,我们会给出非常好的答案。<br /> </span> </p> <p> <span>为什么很多同学学了很多年编程,看了很多书,教程,还是不会写,只能在网络上copy代码?或者自己没有动手能力,遇到稍微复杂的东西就束手无策?为什么那些高效率学习的人,能在三五天内掌握Qt,并开始写软件,做项目?一个类似Qt这样的开发框架,几千个API,如何学习?为什么我们同学学习了一两年Qt C++还糊里糊涂,有的人只需要几天时间就掌握Qt的精髓?<br /> 通过这个系列课程的学习,让学员深入理解一套GUI开发框架,编程思想。并将这套思想应用到任何平台的开发中,例如iOS,Android。 </span> </p> <p> <span>理解这套编程思想,日后可以运用于快速学习任何一套新的东西,框架。</span> </p> 通过这一系列课程的训练,希望大家能达到无招胜有招的境界。达到以后遇到任何客户端软件,拍着胸脯说,我闭着眼睛都能写出来的境界。<br /> <br /> <br /> <br /> <br />
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页