小白学Qt之旅(二)

四、UI进阶

1. Designer 设计师(掌握)

Designer是Qt内置的UI设计工具,可以独立启动,也可以在Qt Creator中使用,其文件格式为.ui。

使用Qt Creator创建项目时,勾选创建界面选项,新创建的项目中的Dialog类会自带一个界面文件,双击即可使用内置的Designer程序打开此文件。

Designer程序的各个区域如下所示。

2. 布局 Layout(掌握)

可以认为布局是一个透明的盒子,内部可以放置不同的组件对象,这些对象在布局中会按照预设的效果自动排布。

布局有四种:

垂直布局

水平布局

● 格点布局

● 表单布局

当布局贴合窗口时,可能会造成组件间距变小的情况,此时可以使用伸展器组件填充空白区域。

伸展器组件本身是不可见的。

选中布局,可以在右下角配置其属性值。

布局和布局之间可以嵌套,内层布局相当于外层布局的一个组件。虽然布局可以嵌套,但是应该在实际开发中尽量避免嵌套。

3. QWidget属性(掌握)

只要是QWidget的派生类对象在Designer中存在,选中此对象后,都可以在右下角的属性配置面板中找到黄色的属性。

4. UI指针(掌握)

ui指针是Qt通过Designer管理组件对象的一种方式,其原理如下所示。

5. 基础组件(熟悉)

5.1 标签 QLabel

用于显示图片或文字。

导入图片到Qt中作为资源的步骤如下:

1. 下载图片并命名为英文小写+下划线+数字的组合,数字不能开头。注意图片不要过大。

2. 把图片放置到工作目录下。

3. 在Qt Creator中选中项目名称,鼠标右键,点击“添加新文件”。

4. 在弹出的窗口中,按照下图所示进行操作。

5. 在弹出的窗口中,按照下图所示进行操作。

6. 在项目管理界面直接点击完成,可以看到项目中会创建一个资源文件,扩展名为qrc

7. 选中qrc资源文件,点击“添加前缀”。

8. 再次选中qrc文件,点击“添加文件”,在弹出的对话框中导入图片文件即可,后续添加图片可以直接从当前步骤开始操作。

9. 可以在qrc文件中看到已经导入的图片。

10. 如果要在Designer中使用此图片,则需要重新构建一次项目;如果要在C++代码中使用此图片,则需要选中在qrc中的图片后,鼠标右键,点击“复制资源路径到剪切板”。

QLabel示例代码下载链接:https://pan.baidu.com/s/1ZBSo8HUsTAr878oYp-hSBA

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.2 按钮类

按钮类组件的继承关系如下所示。

这几个按钮类都继承自QAbstractButton类,QAbstractButton是一个抽象类,内部规定了按钮的基本功能框架。

QAbstractButton的常用属性如下所示。

按钮显示的图片通常为图标,可以从下面的网站下载:

https://www.iconfont.cn/plus

同级互斥,同级可以使用布局,也可以使用QGroupBox组件。

QAbstractButton常用信号函数如下所示。

示例代码下载链接:https://pan.baidu.com/s/1Wca6yu9YNts67q4R6QU_fQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

如果一个窗口内部有若干个按钮对象,需要给这些按钮对象都设置信号槽连接,可以分别给每个按钮对象进行信号槽的连接。此时可以使用QButtonGroup类给若干个按钮进行编组后统一进行信号槽连接处理。

QButtonGroup直接继承QObject类,因此不可见,也不属于ui指针管理,需要在代码汇总手动创建和销毁。

● QButtonGroup::QButtonGroup(QObject * parent = 0)

构造函数

● void QButtonGroup::addButton(QAbstractButton * button, int id = -1)

添加按钮到按钮组

参数1:添加的按钮对象

参数2:按钮编号,正数且不重复

● void QButtonGroup::buttonToggled(int id, bool checked) [signal]

按钮组中的按钮对象选中状态改变时发射的信号函数

参数1:状态改变的按钮对象的编号

参数2:当前此按钮的选中状态

需要注意的是,QCheckBox编组后会变为互斥,需要使用下面的函数解除互斥:

void setExclusive(bool)

参数:是否互斥

按钮组示例代码下载链接:https://pan.baidu.com/s/1-WkRG5WWQDjLzrJr9fYZ6w

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.3 单行文本编辑框 QLineEdit

用于录入一行的用户输入内容。

QLineEdit的常用属性如下所示。

QLineEdit的常用信号函数如下所示。

示例代码下载链接:https://pan.baidu.com/s/11YSOkxvTfaBRw-GtumfeqQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.4 组合框 QComboBox

类似于QRadioButton,组合框提供了另一种单选的方式。

QComboBox常用属性如下所示。

QComboBox常用信号函数如下所示。

示例代码下载链接:https://pan.baidu.com/s/17huvQnOSQ-ea5j136X59SQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.5 一组与数字相关的组件

以下组件都与数字有关。

这些组件常用的属性如下所示。

这些组件常用的信号函数如下所示。

● void valueChanged(int value)

当前数值发生变化时发射的信号

示例代码下载链接:https://pan.baidu.com/s/1pRMAuQoZBC8YCWQSxqtODw

提取码:hqyj

--来自百度网盘超级会员V6的分享

五、常用类

1. QString 字符串类(掌握)

QString是Qt中的字符串类,使用Unicode编码,而不是ASCII码。在C++中字符使用8位的char类型表示一个字符,但是在Qt中使用16位的QChar表示一个字符。因此Qt处理中文没有任何问题,并且一个汉字算作一个字符。

QString类整体使用与std::string类似,但是在API上有所不同。

常用函数如下:

● QString QString::number(int n, int base = 10) [static]

数字→字符串

参数1:要转换的数字

参数2:进制

● QString & QString::setNum(int n, int base = 10)

数字→字符串,支持链式调用

参数1:要转换的数字

参数2:进制

● int QString::toInt(bool * ok = 0, int base = 10) const

字符串→数字

参数1:转换的结果,成功或失败

参数2:进制

返回值:转换的结果,数字;如果失败,返回0。

dialog.cpp

#include "dialog.h"#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :    QDialog(parent),    ui(new Ui::Dialog){    ui->setupUi(this);    QString str = "你好吗αβγāáǎàあいうㅞㅝ";    qDebug() << str.size();    for(int i=0;i<str.size();i++)    {        qDebug() << str.at(i);    }    // 判断字符串是否为空    qDebug() << str.isEmpty();    str.append("fdf");    qDebug() << str;    // 基于16进制转换    int i = 16;    qDebug() << QString::number(i,16);    // 支持链式调用的转换    qDebug() << str.setNum(255,16).prepend("0x");    str = "0";    bool result; // 转换成功或失败的结果    // QString → int    int m = str.toInt(&result,10);    if(result)        qDebug() << "转换成功:" << m;    else        qDebug() << "转换失败:" << m;}Dialog::~Dialog(){    delete ui;}

由于QString类函数众多,无需死记每个函数,只需要把常用的函数单词记住,随用随查即可。

2. 容器类(掌握)

Qt重新实现了C++中的容器类,这些容器类比C++中STL的容器类更加轻巧、安全和易于使用,使用Qt的容器类可以减少可执行文件的大小,Qt的容器类是线程安全的,在基本兼容C++的容器类接口的基础上拓展了新的接口。

分别以QList和QMap为例,进行顺序容器和关联容器的讲解。

2.1 QList

自定义一个C++类,作为QList的元素类型。

下面是创建自定义的C++类的步骤:

1. 在Qt Creator中选中项目名称,鼠标右键,点击“添加新文件”。

2. 在弹出的窗口中,按照下图所示进行操作。

3. 在弹出的窗口中,输入类名后点击“下一步”。

4. 在项目管理界面,直接点击“完成”。可以看到项目中多了新创建的类的头文件和源文件。

QList<Student>示例代码下载链接:https://pan.baidu.com/s/18mb6AsT8mqRcTDrzkAj5-Q

提取码:hqyj

--来自百度网盘超级会员V6的分享

需要注意的是,QStringList类型基本等同QList<QString>,后面不再赘述。

2.2 QMap

示例代码下载链接:https://pan.baidu.com/s/1H_b72YrKr_lyb-7gprYfMQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

3. 跨平台数据类型(了解)

Qt是一个跨平台的开发框架,为了确保在各个平台上的数据类型具有同一的长度,Qt为各种常用的基本数据类型定义了类型符号。

除此之外,Qt中还有一个通用数据类型QVariant,可以对常见的Qt数据类型进行相互转换,也可以使用QVariant类型作为中间类型间接转换不同数据类型。

4. 时间和日期处理(掌握)

Qt拥有若干时间和日期相关类型,本次使用QDateTime类进行讲解。

QDateTime类常用函数如下所示。

● qint64 QDateTime::currentMSecsSinceEpoch() [static]

返回1970年1月1日 0点0分0秒到现在的毫秒数

● QDateTime QDateTime::currentDateTime() [static]

返回一个基于当前时区的时间和日期信息的QDateTime对象

● QString QDateTime::toString(const QString & format) const

返回一个自定义格式的时间日期字符串

参数是自定义的时间和日期格式。

时间和日期相关组件:

示例代码下载链接:https://pan.baidu.com/s/12e2uFhVKmNrnzk2RXqQInA

提取码:hqyj

--来自百度网盘超级会员V6的分享

5. QTimer 定时器类(掌握)

定时器类QTimer主要有两个功能:

● 周期性执行某个动作

● 延迟一段时间后执行某个动作

QTimer类与之前的QButtonGroup一样,需要手动控制堆内存对象的创建和销毁。

QTimer的常用属性如下所示。

● interval : int

如果是一次性的定时器,此属性表示延迟执行的时间;

如果是周期性的定时器,此属性表示间隔执行的时间。

时间单位毫秒。

● singleShot : bool

此属性表示定时器是否是一次性,如果不是一次性就是周期性。

QTImer的常用函数如下所示。

● void QTimer::start() [slot]

开始或重新开始定时器,如果定时器已经在运行,则会停止运行后再次运行。

● void QTimer::stop() [slot]

停止运行

● void QTimer::timeout() [signal]

定时器出发时发射的信号

示例代码下载链接:https://pan.baidu.com/s/1Bji6CfFjEJePVwcvY5pHeA

提取码:hqyj

--来自百度网盘超级会员V6的分享

六、多窗口编程

1. 消息对话框 QMessageBox(掌握)

QDialog是一个对话框窗口类,Qt为了方便程序员调用各种功能的对话框窗口,预设了很多QDialog的派生类,这些派生类分别应用于不同的场景。

这些派生类往往都通过一个静态成员函数调用,通常不需要使用构造函数创建对象。根据不同窗口的功能,这些静态函数会提供当前窗口的信息作为返回值。

QMessageBox是一个用于展示信息或询问用户一个问题的模态对话框,预设的类型有四种:

展示QMessageBox的静态成员函数如下所示。

函数名称可以更换为question、information、warning。

参数1:父对象

参数2:窗口标题

参数3:窗口信息

返回值:用户在弹窗中点击的按钮

2. 常见窗口类的继承关系(掌握)

QWidget类本身也可以创建对象,其构造函数如下所示。

QWidget::QWidget(QWidget * parent = 0)

如果parent参数使用默认值,QWidget对象就是一个独立的窗口;

如果parent参数不使用默认值,QWidget对象会成为其父窗口对象内部的组件。

QMainWidow类通常作为主窗口,因为此类可以增加菜单栏、工具栏、状态栏等。

QWidget类内部也有一些所有的窗口类共有的成员,例如:

● windowTitle : QString

窗口标题

● windowFlags : Qt::WindowFlags

窗口标记

● void QWidget::setWindowState(Qt::WindowStates windowState)

设置窗口状态

示例代码下载链接:https://pan.baidu.com/s/1p9Y-ea-0wEgpscP_iI5FNQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

3. 主窗口类 QMainWindow(掌握)

QMainWindow作为窗口类,包含以下几个部分:

QMenuBar作为菜单栏,内部可以包含若干个菜单QMenu。

QMenu作为菜单,内部可以放置直接触发的QAction对象,也可以继续放置子菜单QMenu,形成二级或多级折叠的菜单。

上面的对象都是肉眼可见的,因此都属于ui指针管理。

QAction的常用信号如下所示。

● void QAction::hovered() [signal]

当鼠标悬停在QAction上发射此信号。

● void QAction::triggered(bool checked = false) [signal]

QAction直接或间接点击触发后发射的信号。

QAction的属性可以在Designer的Action编辑器面板配置,也可以在C++代码中配置。

工具栏上的工具按钮,实际上就是QAction,只需要给QAction设置图标后,在Designer中拖拽上去即可。

中心组件可以包含子组件,是窗口的主要展示内容,可以当做是一个QDialog,与之前的使用无异。

状态栏QStatusBar用于显示一些当前应用程序的状态信息,常用函数如下。

● void QStatusBar::showMessage(const QString & message, int timeout = 0) [slot]

在状态栏展示信息。

参数1:信息内容。

参数2:信息展示的时长,单位毫秒,默认值表示持续显示。

● void QStatusBar::clearMessage() [slot]

清空状态栏显示内容

示例代码下载链接:https://pan.baidu.com/s/1KDJBxLhlnOvpmyfllgMlIg

提取码:hqyj

--来自百度网盘超级会员V6的分享

4. parent参数(掌握)

在Qt各个类的构造函数中经常可以看到parent参数,parent参数传入的对象会作为新创建对象的父对象。对于组件和窗口类,子对象和父对象之间的从属关系比较清晰,例如窗口对象中的组件对象。但是一些非组件或窗口类(例如 QButtonGroup、QTimer等)也有parent参数来设置父对象。

实际上parent参数是Qt内存管理的一个重要环节。

当一个对象创建时设定了父对象,则这个新创建的对象会跟随父对象销毁。Qt中的堆内存对象通常都要传递parent参数,栈内存对象则可以不传递,因为栈内存对象会在局部代码执行完成自动销毁。

堆内存对象创建时不传递parent参数时,需要手动delete,以防止内存泄漏。

示例代码下载链接:https://pan.baidu.com/s/1v3-4eMfIHz-fpCYRSdse1Q

提取码:hqyj

--来自百度网盘超级会员V6的分享

5. 自定义窗口类(掌握)

创建一个自定义的Qt窗口类的步骤如下所示:

1. 在Qt Creator中选中项目名称,鼠标右键,点击“添加新文件”。

2. 在弹出的窗口中,按照下图所示进行操作。

3. 在弹出窗口中,按照下图所示进行操作。

4. 在弹出的窗口中,为新创建的窗口类命名,注意不要使用已经存在的类名。

5. 在项目管理界面,直接点击“完成”。可以看到项目中多了新创建的界面类文件。

示例代码下载链接:https://pan.baidu.com/s/15AUvrSfSAFW1Q0zrdAcC9w

提取码:hqyj

--来自百度网盘超级会员V6的分享

6. 参数传递(掌握)

6.1 主窗口 → 子窗口

主窗口可以通过调用子窗口公开的函数,实现参数传递的效果。

【例子】在主窗口中转动QDial,子窗口的QDial同步转动。

示例代码下载链接:https://pan.baidu.com/s/1Rcg1FkloQSlxh7TbVOZnDg

提取码:hqyj

--来自百度网盘超级会员V6的分享

6.2 子窗口 → 主窗口

子窗口可以通过发射带参数的信号给主窗口接收,实现参数传递的效果。

【例子】在子窗口中转动QDial,主窗口的QDial同步转动。

示例代码下载链接:https://pan.baidu.com/s/1UHxwfvrRpsmw7uppd53WzA

提取码:hqyj

--来自百度网盘超级会员V6的分享

7. 事件机制(掌握)

事件机制是Qt内部的一种消息的传递方式,Qt程序在运行的过程中,不断地处理和转发各种事件信息。

以用户操作鼠标为例:

事件的传递检测可以通过对应类型的事件函数,常用的事件函数如下所示。

void QWidget::paintEvent(QPaintEvent * event) [virtual protected] 绘制

void QWidget::resizeEvent(QResizeEvent * event) [virtual protected] 大小改变

void QWidget::mousePressEvent(QMouseEvent * event) [virtual protected] 鼠标按压

void QWidget::mouseReleaseEvent(QMouseEvent * event) [virtual protected] 鼠标释放

void QWidget::mouseDoubleClickEvent(QMouseEvent * event) [virtual protected] 鼠标双击

void QWidget::mouseMoveEvent(QMouseEvent * event) [virtual protected] 鼠标移动

void QWidget::moveEvent(QMoveEvent * event) [virtual protected] 移动

void QWidget::keyPressEvent(QKeyEvent * event) [virtual protected] 按键按压

void QWidget::keyReleaseEvent(QKeyEvent * event) [virtual protected] 按键释放

void QWidget::focusInEvent(QFocusEvent * event) [virtual protected] 获得焦点

void QWidget::focusOutEvent(QFocusEvent * event) [virtual protected] 失去焦点

void QWidget::closeEvent(QCloseEvent * event) [virtual protected] 关闭

void QWidget::enterEvent(QEvent * event) [virtual protected] 鼠标进入

void QWidget::leaveEvent(QEvent * event) [virtual protected] 鼠标离开

事件函数的使用步骤如下:

1. 找到对应的事件函数

2. 在头文件中声明事件函数

3. 在源文件中定义事件函数

QPainter类是画家类,可以绘制很多底层显示的效果,常用函数如下:

● QPainter::QPainter(QPaintDevice * device)

构造函数,参数是被绘制的对象,只有QPaintDevice的派生类才能被绘制。

● void QPainter::drawPixmap(int x, int y, int width, int height, const QPixmap & pixmap)

画图

参数1:横坐标

参数2:纵坐标

参数3:宽度

参数4:高度

参数5:绘制内容

QKeyEvent类是按键事件的类型,其对象携带了按键事件的相关信息,需要使用的函数如下:

● int QKeyEvent::key() const

返回当前激发的按键码,按键码的对应表查阅Qt文档。

事件函数示例代码下载链接:https://pan.baidu.com/s/1pW6tXz1mLVBg8NvqGc2J6Q

提取码:hqyj

--来自百度网盘超级会员V6的分享

在父组件中可以使用事件过滤器检测事件在子组件的传递过程。

【例子】窗口中有两个QLineEdit,当焦点离开第一个QLineEdit时,窗口背景设置为黑色;当焦点进入第一个QLineEdit时,窗口背景设置为白色。

1. 给需要监控的子组件注册事件过滤器

void QObject::installEventFilter(QObject * filterObj)

参数为父组件

2. 在父窗口中覆盖eventFilter函数

bool QObject::eventFilter(QObject * watched, QEvent * event) [protected virtual]

参数1:被监控的对象,本例中为第一个QLineEdit

参数2:事件对象

返回值:是否拦截

事件过滤器示例代码下载链接:https://pan.baidu.com/s/1sUlfJkUXbw-RweJ8q09K8w

提取码:hqyj

--来自百度网盘超级会员V6的分享

七、文件IO

1. QFileDialog 文件对话框(熟悉)

Qt预设的用于选择文件或目录的对话框窗口类,继承自QDialog。QFileDialog本身不具备IO功能。

调用窗口通过静态成员函数:

此函数可以展示一个用于读取/保存单文件的对话框窗口。

参数1:父对象

参数2:窗口标题

参数3:基于哪个目录,默认为项目的工作目录

参数4:文件类型过滤器

返回值:用户选择的文件路径,如果选择失败,返回空字符串

示例代码下载链接:https://pan.baidu.com/s/1164CVHy6aMW0n3frqGDrmA

提取码:hqyj

--来自百度网盘超级会员V6的分享

2. QFileInfo 文件信息类(熟悉)

QFileInfo类用于获取文件信息。

常用函数如下所示。

● QFileInfo::QFileInfo(const QString & file)

构造函数,参数是文件路径,需要注意的是参数无论是内容,QFileInfo对象都可以创建。

● QDateTime QFileInfo::created() const

返回文件的创建日期和时间

● bool QFileInfo::exists() const

文件是否存在

● bool QFileInfo::isReadable() const

是否可读

● qint64 QFileInfo::size() const

文件大小,返回的单位是字节

示例代码下载链接:https://pan.baidu.com/s/1ofdn02sg5oa1tFBsvcRI5A

提取码:hqyj

--来自百度网盘超级会员V6的分享

3. QFile 文件读写类

QFile类是进行文件读写的类,QIODevice是Qt所有IO类的基类,因此QIODevice类规定了很多IO通用的基础接口。

QFile类的常用函数如下所示。

● QFile::QFile(const QString & name)

构造函数,参数为读写文件的路径

● bool QIODevice::open(OpenMode mode) [virtual]

打开文件读写的数据流,参数为打开的模式。

● bool QIODevice::atEnd() const [virtual]

是否读到文件尾

● QByteArray QIODevice::read(qint64 maxSize)

读取最大字节数的数据,参数是最大字节数,返回值是读取后的字节数组对象。

● qint64 QIODevice::write(const QByteArray & byteArray)

写出数据到文件,参数为需要写出的数据,返回值是实际写出的数据量,如果返回-1表示写出错误。

● void QIODevice::close() [virtual]

关闭数据流

● qint64 QIODevice::size() const [virtual]

获取可读的字节数

示例代码下载链接:https://pan.baidu.com/s/1oubhQtEgr3suJe2lNCUoPQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

4. UI与耗时操作

在默认的情况下,程序员编写Qt程序只在一个线程(主线程)中运行。但是有时候这个线程会出现一些耗时操作(例如文件IO、网络、复杂算法等),这些耗时操作会导致主线程阻塞,此时用户发起的一些常规UI操作就无法得到及时的响应,此时操作系统检测一些关闭等UI操作无法及时响应则会弹出程序未响应窗口。

Windows等桌面操作系统会引导用户选择关闭还是等待。

解决方案就是使用多线程,主线程只执行UI相关操作,子线程执行耗时操作

5. QThread 线程类(掌握)

5.1 复现未响应

QThread类是Qt的线程类,其中有一个静态成员函数:

● void QThread::msleep(unsigned long msecs) [static]

使当前线程强制睡眠,参数为睡眠时间,单位毫秒。

示例程序下载链接:https://pan.baidu.com/s/1XUGFqSnItEJ4B7nEAd9gqw

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.2 创建并启动线程

创建并启动一个线程的步骤如下:

1. 在Qt Creator中选中项目名称后,鼠标右键,点击“添加新文件”。

2. 在弹出的窗口中,按照下图所示配置自定义线程类信息。

3. 在“项目管理”界面,直接点击“完成”。可以在项目中看到,线程类已经创建完成。

4. 在自定义线程类中,覆盖QThread类中的run函数。

void QThread::run() [virtual protected]

此函数是子线程的起始点,此函数执行完成后,子线程也执行结束。

5. 在run函数中编写子线程要执行的代码,此函数不能包含UI操作。

6. 在主线程中创建子线程类对象,并调用start函数启动子线程。

void QThread::start(Priority priority = InheritPriority) [slot]

参数为线程执行的优先级。

示例代码下载链接:https://pan.baidu.com/s/19f7QEtBQaj8d6_H347wxcA

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.3 优先级

不同的线程对象可以拥有不同的优先级,优先级代表cpu的一种选择偏向,具体取决于cpu对线程的调度。

除了使用start函数在启动时直接设置优先级外,当线程运行时,也可以使用下面的函数设置优先级;如果线程没有运行,此函数无效。

● void QThread::setPriority(Priority priority)

参数为不同的优先级。

示例代码下载链接:https://pan.baidu.com/s/1JpfcJJcO4-Du1ppqK6oxaA

提取码:hqyj

--来自百度网盘超级会员V6的分享

5.4 线程停止

在实际的开发中尽量不要停止线程,本次提供两种停止的方式:

1. 调用terminate函数

void QThread::terminate() [slot]

强行停止线程执行

2. 给耗时操作循环体设置标志位,通过设置标志位的数值,停止循环,间接使run函数执行完毕,从而达到停止线程的效果。

示例代码下载链接:https://pan.baidu.com/s/1yx2Wq-GO3cM56lfviigmZQ

提取码:hqyj

--来自百度网盘超级会员V6的分享

在上面的代码中,子线程执行了耗时操作(循环睡眠),主线程接收子线程操作的通知,在实际的开发中,主线程接收到子线程耗时操作的通知后可能会刷新UI显示(例如显示文件读写的进度),这种情况下需要使用信号槽进行两个线程之间的通信。

多线程文件拷贝器代码下载链接:https://pan.baidu.com/s/1SQLKqI7LP0EhkGZTzJJDUw

提取码:hqyj

--来自百度网盘超级会员V6的分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值