当前位置: 首页 > news >正文

Qt基础终结篇:从文件操作到多线程异步UI,深度解析核心要点

文章目录

  • 前言
  • 一、QFileDialog 文件对话框
  • 二、QFileInfo 文件信息类
  • 三、QFile 文件读写类
  • 四、UI与耗时操作:避免UI卡顿与程序未响应
  • 五、多线程
  • 六、异步刷新与线程通信
  • 总结


前言

上一篇文章,我们已经把qt的基础知识讲解的差不多了。本文我们将继续进行qt的学习,并且一口气把qt的基础知识讲解完。大家可以根据目录的指引来快速获取自己需要的知识和内容,那么文章就从这里开始吧。


一、QFileDialog 文件对话框

QFileDialog 是 Qt 框架中用于提供标准文件选择对话框的类。它允许用户选择一个文件进行打开(读取)或保存(写入)。

核心特点:

纯界面类: QFileDialog 本身不执行文件的实际读写操作。它只负责提供一个用户界面,让用户选择文件路径。一旦用户选择了文件,它会返回该文件的路径字符串,后续的文件操作(如打开、读取、写入)需要由应用程序自行处理。
静态方法: 最常用的文件选择功能通过其静态方法提供,这意味着你不需要创建 QFileDialog 的实例就可以直接调用它们。

常用静态函数:
QFileDialog 提供了方便的静态方法来弹出“打开文件”或“保存文件”的对话框。

  1. getOpenFileName() - 弹出“打开文件”对话框

功能: 允许用户选择一个已存在的文件进行打开(通常是读取)。

QString QFileDialog::getOpenFileName(QWidget * parent = 0,const QString & caption = QString(),const QString & dir = QString(),const QString & filter = QString()
) [static]

返回值:
如果用户选择了一个文件并点击“打开”,则返回所选文件的完整路径字符串。
如果用户取消了对话框(例如点击“取消”按钮或关闭窗口),则返回一个空字符串。

  1. getSaveFileName() - 弹出“保存文件”对话框

功能: 允许用户指定一个文件路径来保存数据。用户可以选择一个现有文件进行覆盖,或者输入一个新文件名来创建新文件。

QString QFileDialog::getSaveFileName(QWidget * parent = 0,const QString & caption = QString(),const QString & dir = QString(),const QString & filter = QString()
) [static]

返回值:
如果用户指定了一个文件路径并点击“保存”,则返回所指定文件的完整路径字符串。
如果用户取消了对话框,则返回一个空字符串。

参数详解(适用于 getOpenFileName 和 getSaveFileName)

QWidget * parent = 0

类型: QWidget 指针
作用: 指定文件对话框的父窗口。
影响:
如果指定了父窗口,对话框将以模态(modal)方式显示,并居中于父窗口。这意味着用户必须先关闭文件对话框才能与父窗口进行交互。
如果为 0(默认值),对话框将作为顶级窗口显示,并且可能不会居中于任何特定窗口。
建议: 强烈建议指定父窗口,以提供更好的用户体验和窗口管理。

const QString & caption = QString()

类型: QString
作用: 设置文件对话框的标题栏文本。
默认值: 空字符串,此时系统会提供默认标题(例如“打开文件”或“保存文件”)。
示例: “选择图片文件”,“保存文档”

const QString & dir = QString()

类型: QString
作用: 指定对话框打开时最初显示的目录路径。
默认值: 空字符串,此时对话框通常会从应用程序的当前工作目录(或用户上次访问的目录,取决于操作系统和Qt版本)开始。
示例: “C:/Users/YourName/Documents”,“/home/user/images”
注意: 如果指定的目录不存在,对话框可能会回退到默认行为。

const QString & filter = QString()

类型: QString
作用: 定义文件类型过滤器,用于限制用户可以看到和选择的文件类型。
默认值: 空字符串,表示显示所有文件类型。
格式: 过滤器字符串由一个或多个过滤器项组成,每个项的格式为:“描述 (.扩展名1 .扩展名2);;描述2 (.扩展名3)"
描述: 用户在下拉菜单中看到的文本。
.扩展名: 匹配的文件扩展名。可以使用通配符
;;: 用于分隔多个过滤器项。
示例:
"图片文件 (
.png .jpg .jpeg);;文本文件 (.txt);;所有文件 (.
)"
"C++ 源文件 (
.cpp .h);;Qt 项目文件 (.pro)”
注意: 过滤器只影响显示的文件,用户仍然可以通过手动输入文件名来选择不符合过滤器的文件(在某些操作系统上)。

代码示例
代码包


二、QFileInfo 文件信息类

QFileInfo 类用于获取文件的各种信息,例如文件是否存在、文件大小、上次修改时间等。它提供了多种成员函数来访问这些属性。

构造函数

QFileInfo::QFileInfo(const QString &file)

参数: file - 文件的完整路径(包括文件名)。
说明: 使用指定的文件路径构造一个 QFileInfo 对象。在构造之后,你可以使用该对象的成员函数来查询文件的各种属性。
常用成员函数

bool QFileInfo::exists() const

返回值: 如果文件或目录存在,则返回 true;否则返回 false。
说明: 用于检查由 QFileInfo 对象表示的文件或目录是否存在于文件系统中。

qint64 QFileInfo::size() const

返回值: 文件的字节大小。如果文件不存在或无法访问,则返回 0。
说明: 返回文件的大小,单位是字节。对于目录,此函数通常返回 0。

QDateTime QFileInfo::lastModified() const

返回值: 一个 QDateTime 对象,包含文件的上次修改日期和时间。如果文件不存在或无法访问,则返回一个无效的 QDateTime 对象。
说明: 获取文件的最后修改时间戳。QDateTime 对象可以进一步格式化或用于时间比较。

代码示例

代码包


三、QFile 文件读写类

QFile类是Qt中用于文件操作的核心类,它间接继承自QIODevice类。QIODevice类是Qt所有IO类的基类,提供了许多读写的基础接口。

核心功能概述
QFile提供了方便的文件创建、打开、读写和关闭操作。它通过其基类QIODevice继承了通用的IO操作接口,并为文件系统特有的行为(如文件路径、权限等)提供了封装。

相关函数
以下是QFile和其基类中常用的一些函数:

  1. 构造函数
QFile::QFile(const QString & name)

作用: 构造一个QFile对象。
参数: name (const QString &) - 指定要操作的文件的路径和名称。
备注: 构造函数只是创建了QFile对象并设置了文件路径,并不会立即打开文件。

  1. 文件流操作
bool QIODevice::open(OpenMode mode)

作用: 打开文件流。这是在读写文件之前必须调用的函数。
参数: mode (OpenMode) - 指定打开文件的模式。OpenMode是一个枚举类型,可以组合使用(例如:QIODevice::ReadOnly | QIODevice::Text)。
常用模式举例:
QIODevice::ReadOnly: 只读模式。文件必须存在。
QIODevice::WriteOnly: 只写模式。如果文件不存在则创建,如果存在则清空内容。
QIODevice::ReadWrite: 读写模式。
QIODevice::Append: 追加模式。写入的数据会添加到文件末尾。
QIODevice::Truncate: 清空模式。打开文件时会清空文件内容。
QIODevice::Text: 文本模式。在Windows上,将\r\n转换为\n,反之亦然。
返回值: bool - 如果成功打开文件则返回true,否则返回false。
备注: 建议在使用后检查返回值,以确保文件成功打开。

void QIODevice::close()

作用: 关闭文件流。释放文件资源。
备注: 在文件操作完成后,务必调用此函数来关闭文件,以避免资源泄露或数据丢失。

  1. 数据读取
QByteArray QIODevice::read(qint64 maxSize)

作用: 从文件流中读取指定最大字节数的数据。
参数: maxSize (qint64) - 要读取的最大字节数。
返回值: QByteArray - 包含读取到的数据的字节数组。如果达到文件末尾或发生错误,返回的QByteArray可能小于maxSize或为空。
备注: 该函数会尝试读取最多maxSize个字节,但可能因为文件剩余内容不足或到达文件末尾而读取更少的数据。

qint64 QIODevice::bytesAvailable() const

作用: 返回流中当前可供读取的剩余字节数。
返回值: qint64 - 可用的字节数。
备注: 在读取文件时,可以使用此函数来判断是否还有数据可读,或者一次性读取所有剩余数据。

  1. 数据写入
qint64 QIODevice::write(const QByteArray & byteArray)

作用: 将QByteArray中的数据写入文件流。
参数: byteArray (const QByteArray &) - 要写入的数据。
返回值: qint64 - 实际写入的字节数。如果发生错误,可能返回-1或小于byteArray.size()的值。
备注: 在写入后,应检查返回值以确保所有数据都已成功写入。

  1. 缓冲区操作
bool QFileDevice::flush()

作用: 清空文件设备的内部写缓冲区,将所有缓存的数据强制写入底层设备(例如硬盘)。
返回值: bool - 如果刷新成功则返回true,否则返回false。
备注: 写入操作通常是先写入内存缓冲区,再由操作系统或文件系统异步写入磁盘。flush()可以强制将数据立即写入磁盘,这在确保数据持久性(例如在关键操作后或程序退出前)时非常有用。

代码示例
代码包


四、UI与耗时操作:避免UI卡顿与程序未响应

  1. 主线程(UI线程)的职责:

程序启动时,默认只有一个线程,即主线程(也称为UI线程)。
主线程的核心职责是处理所有Qt基础事件和UI操作,确保用户界面的流畅响应。

  1. 耗时操作对主线程的影响:

当耗时较长的操作(例如:读写大文件、复杂的计算、网络请求等)在主线程中执行时,主线程会被这些操作“占用”或“阻塞”。
被阻塞的主线程无法及时处理UI事件(如点击、滚动、窗口重绘等),导致用户界面出现卡顿、假死现象。
如果阻塞时间过长,操作系统会认为程序失去了响应,并可能弹出“程序未响应”的提示窗口,严重影响用户体验。

  1. 解决方案:分离耗时操作到子线程:

为了保持UI的流畅和程序的响应性,解决卡顿问题的根本方法是:将所有耗时较长的操作从主线程中分离出来。
这些耗时操作应该被移到独立的“子线程”中执行。
子线程在后台默默工作,而主线程则继续专注于UI事件的处理,从而确保用户界面的持续响应和良好的用户体验。


五、多线程

QThread 类是 Qt 提供的用于多线程编程的类。它封装了平台相关的线程API,提供了一个方便、跨平台的接口来创建和管理线程。

QThread 类核心函数:

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

描述: 强制当前线程睡眠 msecs 毫秒。这是一个静态函数,可以在任何线程中调用,使该线程进入休眠状态。常用于模拟耗时操作。

void QThread::run() [virtual protected]

描述: 这是子线程的起始点。当你调用 QThread::start() 函数后,QThread 内部会自动调用这个 run() 函数。你需要继承 QThread 类并覆盖(override)这个函数,将所有需要在子线程中执行的耗时操作放在这个 run() 函数的实现中。

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

描述: 启动子线程。调用此函数后,QThread 会创建一个新的操作系统线程,并在该线程中执行你的 run() 函数。priority 参数可以设置线程的优先级,通常保持默认即可。

创建并开启一个子线程的详细步骤:

在Qt Creator中创建新的C++ Class文件:

在Qt Creator的“项目”视图中,右键点击你的项目名称。
选择“添加新文件…”。
在弹出的对话框中,选择“C++ Class”。

配置类信息:
通常会提示你输入类名、基类等信息。
类名: 例如 MyThread (你可以根据自己的需求命名)。
基类 (Base Class): 选择 QThread。
确保勾选“头文件”和“源文件”的选项,Qt Creator会自动为你生成 mythread.h 和 mythread.cpp (如果你的类名是MyThread)。

完成类创建:
直接点击“完成”按钮。现在你的项目中会多了 mythread.h 和 mythread.cpp 两个文件。

代码示例
代码包


六、异步刷新与线程通信

在实际开发中,特别是涉及到用户界面(UI)的应用,异步刷新是一个至关重要的概念。它解决了在UI线程上执行耗时操作所导致的界面冻结问题。而实现异步刷新的核心,就是主线程和子线程之间的通信。

  1. 为什么需要异步刷新?
    主线程不能执行耗时操作:

主线程(通常也称为UI线程)负责处理用户交互、绘制UI界面等任务。
如果主线程执行耗时操作(如网络请求、数据库查询、大文件读写、复杂计算),它会被阻塞,导致UI无响应、用户体验极差,甚至可能被操作系统判定为“应用程序无响应”(ANR)。

UI操作是线程不安全的: 多数UI框架(如Android的View体系,Java Swing/AWT,.NET WinForms/WPF)规定,所有对UI组件的修改必须在主线程上执行。这是为了避免并发访问UI组件时出现数据不一致或绘制错误。

子线程不能执行UI操作:
子线程的创建是为了执行耗时操作,从而不阻塞主线程。
直接在子线程中操作UI组件会导致应用程序崩溃、行为异常或不可预测的UI状态。

  1. 线程通信的本质:父对象与子对象的通信
    正如内容中提到的,“主线程往往是子线程的父对象,因此线程通信问题本质上就是父对象和子对象的通信问题。”这是一种非常形象且准确的理解。

子线程(“子对象”)执行任务并报告结果: 子线程启动后,执行它的耗时任务。任务完成后,它需要将结果(或者任务完成的状态)通知给主线程。
主线程(“父对象”)接收通知并更新UI: 主线程接收到子线程的通知后,根据通知的内容,在主线程上执行相应的UI更新操作。

代码示例
代码包

示例:多线程文件拷贝器
代码包


总结

本文作为Qt基础知识的“终结篇”,系统地梳理并深入讲解了Qt应用程序开发中的几个关键模块:QFileDialog文件对话框、QFileInfo文件信息类、QFile文件读写类,以及至关重要的多线程编程。文章首先详细介绍了如何使用QFileDialog进行文件选择,以及QFileInfo获取文件元数据。随后,深入探讨了QFile的文件打开、读写操作及其缓冲机制。为了解决UI卡顿和程序未响应问题,文章重点阐述了多线程的必要性,详细讲解了QThread的使用方法,并强调了主线程与子线程间异步刷新和通信的本质。通过详细的理论解析和代码示例,旨在帮助读者掌握Qt中文件操作的实用技巧和多线程编程的核心思想,为构建响应迅速、用户体验良好的Qt应用打下坚实基础。

相关文章:

  • Excel 操作 转图片,转pdf等
  • 新编辑器编写指南--给自己的备忘
  • 【数据结构】——二叉树堆(下)
  • 【深度学习】7. 深度卷积神经网络架构:从 ILSVRC、LeNet 到 AlexNet、ZFNet、VGGNet,含pytorch代码结构
  • uni-app学习笔记十五-vue3页面生命周期(一)
  • pycharm终端遇不显示虚拟环境的问题
  • 【第1章 基础知识】1.8 在 Canvas 中使用 HTML 元素
  • WPF【11_3】WPF实战-重构与美化(可复用的UI组件)
  • 【AI工具应用】使用 trae 实现 word 转成 html
  • PH热榜 | 2025-05-24
  • 【Linux】shell脚本的常用命令
  • winform LiveCharts2的使用--图表的使用
  • Linux 使用 Docker 安装 Milvus的两种方式
  • 微信小程序的软件测试用例编写指南及示例--性能测试用例
  • 【CSS】CSS 和 SASS 的区别
  • 【平面波导外腔激光器专题系列】用于光纤传感的低噪声PLC外腔窄线宽激光器
  • 【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,把想要打印的界面打印成图片
  • 理解 Kubernetes 的架构与控制平面组件运行机制
  • 【洛谷P9303题解】AC- [CCC 2023 J5] CCC Word Hunt
  • word批量导出visio图
  • 网站上传的流程图/企业网站设计模板
  • 带紫色箭头做网站软件/百度官网推广平台
  • 电商平台运营模式/深圳关键词优化怎么样
  • 中国建设银行企业信息门户网站/微信小程序开发流程
  • 免费网页设计模板网站/网络营销促销方案
  • 有没有专门做av字幕的网站/引擎优化seo怎么做