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

Qt 进度条与多线程应用、基于 Qt 的文件复制工具开发

练习1:Qt 进度条与多线程应用

题目描述

开发一个基于 Qt 的应用程序,该应用程序包含一个水平进度条(QSlider),并且需要通过多线程来更新进度条的值。请根据以下要求完成代码:

  1. 界面设计

    • 使用 QSlider 控件作为进度条。

    • 设置 QSlider 的样式

  2. 多线程更新

    • 创建一个自定义线程类 mythread,该线程类继承自 QThread

    • 使主线程接收到信号后,更新 QSlider 的值。

  3. 信号与槽

    • 使用信号与槽机制实现线程与主线程之间的通信。

    • 当线程中的值发生变化时,通过信号通知主线程更新进度条。

1.mythread.h 

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include<QThread>

class mythread : public QThread
{
    Q_OBJECT
public:

    explicit mythread(QObject *parent = nullptr);
    void run() override; // 线程的执行函数

signals:
    void updateValue(int value); // 发送信号更新进度条
};


#endif // MYTHREAD_H

2.mythread.cpp 

#include "mythread.h"
#include<QThread>

mythread::mythread(QObject *parent){}
void mythread::run()
{
    int value = 0;
    while (true) {
        emit updateValue(value);
        value = (value + 1) % 101;  // 0 ~ 100 循环
        QThread::msleep(100);  // 休眠 100ms
    }
}

3.widget.h 

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QWidget>
#include <QMovie>
#include <QThread>
#include <QTextEdit>
#include <QWidget>
#include <QThread>
#include<QScreen>
#include<QLabel>
#include<QDebug>
#include<QPixmap>
#include<QApplication>
#include<QPushButton>
#include "mythread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT
public slots:
    void setSliderValue(int value); // 更新进度条

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    mythread *thread;
};
#endif // WIDGET_H

4.widget.cpp 

#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QString qss = "QSlider { background: transparent; }"//设置 QSlider 的背景为透明
                  "QSlider::groove:horizontal { border: 1px solid gray; background: lightgray; height: 15px; border-radius: 5px; }"
                  "QSlider::sub-page:horizontal { background: #B5E61D; border-radius: 5px; }"
                  "QSlider::handle:horizontal { background:#5A730E; width: 10px;border-radius: 5px }";


    ui->horizontalSlider->setStyleSheet(qss);

    // 创建并启动线程
        thread = new mythread(this);
        connect(thread, &mythread::updateValue, this, &Widget::setSliderValue);
        thread->start();
    }


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

// 槽函数:更新进度条
void Widget::setSliderValue(int value)
{
    ui->horizontalSlider->setValue(value);
}

练习2:基于 Qt 的文件复制工具开发

开发一个基于 Qt 的文件复制工具,要求实现以下功能:

  1. 文件选择

    • 使用 QFileDialog 选择源文件和目标文件。

    • 支持选择大文件(超过 800MB)。

  2. 文件复制

    • 使用 Qt 的文件 IO 操作(QFile)实现文件复制功能。

    • 支持分块读取和写入文件,避免一次性加载大文件到内存中。

  3. 多线程处理

    • 使用 QThread 在后台执行文件复制操作,避免阻塞主线程。

    • 通过信号与槽机制,将复制进度实时传递给主线程。

  4. 进度显示

    • 使用自定义的 QSlider 作为进度条,显示文件复制的进度。

    • 自定义 QSlider 的样式,使其外观美观。

  5. 错误处理

    • 如果文件打开失败或复制失败,弹出错误提示框。

    • 如果复制完成,弹出提示框显示“文件复制完成”。

1.mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QString>

class MyThread : public QThread
{
    Q_OBJECT

public:
    explicit MyThread(const QString &source, const QString &destination, QObject *parent = nullptr);

signals:
    void progressUpdated(int value); // 信号:用于更新进度条的值

protected:
    void run() override; // 线程执行函数

private:
    QString sourcePath;  // 源文件路径
    QString destinationPath; // 目标文件路径
};

#endif // MYTHREAD_H

2.mythread.cpp 

#include "mythread.h"
#include <QFile>
#include <QDebug>

MyThread::MyThread(const QString &source, const QString &destination, QObject *parent)
    : QThread(parent), sourcePath(source), destinationPath(destination)
{
}

void MyThread::run()
{
    QFile sourceFile(sourcePath);
    QFile destinationFile(destinationPath);

    // 打开源文件
    if (!sourceFile.open(QIODevice::ReadOnly)) {
        emit progressUpdated(-1); // 发送错误信号
        return;
    }

    // 打开目标文件
    if (!destinationFile.open(QIODevice::WriteOnly)) {
        emit progressUpdated(-1); // 发送错误信号
        return;
    }

    qint64 fileSize = sourceFile.size(); // 获取文件大小
    qint64 bytesCopied = 0; // 已复制的字节数
    char buffer[4096]; // 缓冲区

    // 分块读取和写入文件
    while (!sourceFile.atEnd()) {
        qint64 bytesRead = sourceFile.read(buffer, sizeof(buffer)); // 读取数据
        destinationFile.write(buffer, bytesRead); // 写入数据
        bytesCopied += bytesRead; // 更新已复制的字节数
        int progress = static_cast<int>((bytesCopied * 100) / fileSize); // 计算进度
        emit progressUpdated(progress); // 发送进度信号
    }

    // 关闭文件
    sourceFile.close();
    destinationFile.close();
}

3.widget.h 

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSlider>
#include <QFileDialog>
#include <QMessageBox>
#include "mythread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void updateProgress(int value); // 槽函数:更新进度条

private:
    Ui::Widget *ui;
    MyThread *thread; // 文件复制线程
};

#endif // WIDGET_H

 4.widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置 QSlider 的样式
    QString qss = "QSlider { background: transparent; }" // 设置 QSlider 的背景为透明
                  "QSlider::groove:horizontal { border: 1px solid gray; background: lightgray; height: 15px; border-radius: 5px; }"
                  "QSlider::sub-page:horizontal { background: #B5E61D; border-radius: 5px; }"
                  "QSlider::handle:horizontal { background:#5A730E; width: 10px; border-radius: 5px; }";

    ui->horizontalSlider->setStyleSheet(qss);
    ui->horizontalSlider->setRange(0, 100); // 设置进度条范围
    ui->horizontalSlider->setValue(0); // 初始值为 0

    // 选择源文件
    QString sourceFile = QFileDialog::getOpenFileName(this, "选择要复制的文件");
    if (sourceFile.isEmpty()) {
        QMessageBox::warning(this, "警告", "未选择源文件");
        return;
    }

    // 选择目标文件
    QString destinationFile = QFileDialog::getSaveFileName(this, "选择保存位置");
    if (destinationFile.isEmpty()) {
        QMessageBox::warning(this, "警告", "未选择目标文件");
        return;
    }

    // 创建并启动线程
    thread = new MyThread(sourceFile, destinationFile, this);
    connect(thread, &MyThread::progressUpdated, this, &Widget::updateProgress);
    thread->start();
}

Widget::~Widget()
{
    if (thread) {
        thread->quit(); // 停止线程
        thread->wait(); // 等待线程结束
        delete thread; // 释放线程对象
    }
    delete ui;
}

// 槽函数:更新进度条
void Widget::updateProgress(int value)
{
    if (value == -1) {
        QMessageBox::critical(this, "错误", "文件复制失败");
        return;
    }
    ui->horizontalSlider->setValue(value); // 更新 QSlider 的值
    if (value == 100) {
        QMessageBox::information(this, "完成", "文件复制完成");
    }
}


http://www.kler.cn/a/579010.html

相关文章:

  • NO.32十六届蓝桥杯备战|函数|库函数|自定义函数|实参|形参|传参(C++)
  • 系统架构评估方法-ATAM方法
  • SQL根据分隔符折分不同的内容放到临时表
  • 【SpringBoot】深入剖析 Spring Boot 自动装配原理(附源码与实战)
  • vue3 vite项目安装eslint
  • python将目录下的所欲md文件转化为html和pdf
  • JVM常用概念之移动GC和局部性
  • k8s下部署ansible进行node-export二安装
  • electron builder打包时,出现errorOut=ERROR: Cannot create symbolic link
  • 【AVRCP】协议深入解析(1):从框架到数据单元
  • 负载均衡集群和高可用集群
  • 【神经网络】0.深度学习基础:解锁深度学习,重塑未来的智能新引擎
  • chatgpt完成python提取PDF简历指定内容的案例
  • 【2025深夜随笔】简单认识一下Android Studio
  • kafka单机部署实战
  • 10分钟看明白爆火的本地知识库! 掌握本地知识库基本概念与RAG的完整架构
  • C++学习之格斗小游戏综合案例
  • 6-5,web3浏览器链接区块链(react+区块链实战)
  • 【已解决】AttributeError: module ‘numpy‘ has no attribute ‘object‘.
  • css实现元素垂直居中显示的7种方式