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

QT.....................................5

1:是进度条通过线程自己动起来

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class myThread : public QThread
{
    Q_OBJECT
public:
    explicit myThread(QObject* parent = nullptr);
    void setRunning(bool running);  // 控制线程运行状态

signals:
    void updateSlider(int value);   // 更新滑块的信号

protected:
    void run() override;

private:
    bool m_running = false;        // 线程运行状态标志
    QMutex m_mutex;                // 线程锁保证状态同步
    int m_currentValue = 0;        // 当前滑块值
    int m_direction = 1;           // 移动方向(1前进,-1后退)
};

#endif // MYTHREAD_H

mythread.cpp

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

myThread::myThread(QObject* parent)
    : QThread(parent)
{
    qDebug() << "线程创建";
}

void myThread::setRunning(bool running)
{
    QMutexLocker locker(&m_mutex);
    m_running = running;
}

void myThread::run()
{
    qDebug() << "线程启动";
    {
        QMutexLocker locker(&m_mutex);
        m_running = true;
    }

    while(true) {
        { // 检查运行状态
            QMutexLocker locker(&m_mutex);
            if(!m_running) break;
        }

        // 更新滑块值
        m_currentValue += m_direction;

        // 边界检测
        if(m_currentValue >= 100) {
            m_currentValue = 100;
            m_direction = -1;
        }
        else if(m_currentValue <= 0) {
            m_currentValue = 0;
            m_direction = 1;
        }

        // 发送更新信号
        emit updateSlider(m_currentValue);

        // 线程休眠(控制移动速度)
        msleep(50);
    }
    qDebug() << "线程退出";
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

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

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

protected:
    void closeEvent(QCloseEvent *event) override;

private slots:
    void onSliderValueChanged(int value);  // 处理滑块值更新

private:
    Ui::Widget *ui;
    myThread* m_thread;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QCloseEvent>

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

    // 初始化滑块
    ui->horizontalSlider->setRange(0, 100);
    ui->horizontalSlider->setValue(0);

    // 设置样式
    QString qss =R"(
                 QSlider::groove:horizontal {
                     background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                         stop:0 #FF007F, stop:0.25 #FF00FF,
                         stop:0.5 #00FFFF, stop:0.75 #00FF7F,
                         stop:1 #00FF00);
                     height: 10px;
                     border-radius: 5px;
                 }

                 QSlider::sub-page:horizontal {
                     background: rgba(255, 255, 255, 0.3);
                     border-radius: 5px;
                 }

                 QSlider::handle:horizontal {
                     background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5,
                         fx:0.5, fy:0.5,
                         stop:0 white, stop:0.5 #FFD700,
                         stop:1 #FFA500);
                     width: 20px;
                     height: 20px;
                     margin: -5px 0;
                     border-radius: 10px;
                     border: 2px solid #FFFFFF;
                     box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5);
                 }

                 QSlider::handle:horizontal:hover {
                     background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5,
                         fx:0.5, fy:0.5,
                         stop:0 white, stop:0.5 #FFD700,
                         stop:1 #FF4500);
                     border: 2px solid #FFD700;
                 }
             )";
    ui->horizontalSlider->setStyleSheet(qss);

    // 连接信号槽
    connect(m_thread, &myThread::updateSlider,
            ui->horizontalSlider, &QSlider::setValue);
    connect(m_thread, &myThread::updateSlider,
            this, [](int val){ qDebug() << "当前滑块值:" << val; });

    // 启动线程
    m_thread->start();
}

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

void Widget::closeEvent(QCloseEvent *event)
{
    // 安全停止线程
    m_thread->setRunning(false);
    m_thread->quit();
    m_thread->wait();
    event->accept();
}

void Widget::onSliderValueChanged(int value)
{
    // 可根据需要添加额外处理
}

2:使用QFileDialog 或者 拖放事件 + QT文件IO + QT线程

实现一个文件复制功能,要求能够复制大小超过800mb的文件

额外要求:可以在文件拷贝的时候,追加一个进度条显示拷贝了多少文件内容

mythread2.h

#ifndef MYTHREAD2_H
#define MYTHREAD2_H

#include <QThread>
#include <QFile>

class mythread2 : public QThread
{
    Q_OBJECT
public:
    explicit mythread2(const QString &source, const QString &dest, QObject* parent = nullptr);

signals:
    void progressChanged(int value);
    void copyFinished(bool success, const QString &message);

protected:
    void run() override;

private:
    QString m_source;
    QString m_dest;
};

#endif // MYTHREAD2_H

mythread2.cpp

#include "mythread2.h"
#include <QDir>
#include <QDebug>

mythread2::mythread2(const QString &source, const QString &dest, QObject* parent)
    : QThread(parent), m_source(source), m_dest(dest)
{
    qDebug() << "文件复制线程创建,源文件:" << source;
}

void mythread2::run()
{
    qDebug() << "开始文件复制操作...";

    QFile srcFile(m_source);
    QFile destFile(m_dest);

    // 打开源文件(只读模式)
    if (!srcFile.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开源文件:" << m_source;
        emit copyFinished(false, "无法打开源文件");
        return;
    }

    // 创建目标文件(只写模式)
    if (!destFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法创建目标文件:" << m_dest;
        srcFile.close();
        emit copyFinished(false, "无法创建目标文件");
        return;
    }

    const qint64 bufferSize = 1024 * 1024; // 1MB缓冲区
    char *buffer = new char[bufferSize];
    qint64 totalBytes = srcFile.size();
    qint64 bytesCopied = 0;

    qDebug() << "开始复制,文件总大小:" << totalBytes << "bytes";

    while (!srcFile.atEnd()) {
        // 检查线程中断请求
        if (this->isInterruptionRequested()) {
            qDebug() << "收到中断请求,停止复制";
            break;
        }

        // 读取文件内容
        qint64 readBytes = srcFile.read(buffer, bufferSize);
        if (readBytes == -1) {
            qWarning() << "读取文件错误,位置:" << bytesCopied;
            emit copyFinished(false, "读取文件错误");
            break;
        }

        // 写入目标文件
        qint64 writeBytes = destFile.write(buffer, readBytes);
        if (writeBytes != readBytes) {
            qWarning() << "写入文件错误,预期写入:" << readBytes << "实际写入:" << writeBytes;
            emit copyFinished(false, "写入文件错误");
            break;
        }

        // 更新进度
        bytesCopied += readBytes;

        // 计算进度百分比(使用浮点运算避免溢出)
        int progress = 0;
        if (totalBytes > 0) {
            progress = static_cast<int>((static_cast<double>(bytesCopied) / totalBytes) * 100);
        }
        emit progressChanged(progress);

        // 调试输出(生产环境应注释掉)
        qDebug() << "已复制:" << bytesCopied << "bytes (" << progress << "%)";
    }

    // 清理资源
    delete[] buffer;
    srcFile.close();
    destFile.close();

    // 处理最终结果
    if (bytesCopied == totalBytes) {
        qDebug() << "文件复制完成,总字节:" << bytesCopied;
        emit copyFinished(true, QFileInfo(m_source).fileName() + " 文件已存放成功");
    } else {
        qWarning() << "复制中断,已复制:" << bytesCopied << "/" << totalBytes;
        QFile::remove(m_dest); // 删除不完整文件
        emit copyFinished(false, "文件复制中断");
    }
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "mythread2.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_clicked();
    void updateProgress(int value);
    void handleCopyResult(bool success, const QString &message);

private:
    Ui::Widget *ui;
    mythread2 *m_copyThread;
    QString m_targetDir = "D:/QT.存放文件";
};

#endif // WIDGET_H

widget.cpp

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

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

    // 初始化目标目录
    QDir dir(m_targetDir);
    if (!dir.exists()) {
        qDebug() << "创建目标目录:" << m_targetDir;
        dir.mkpath(".");
    }

    // 配置进度条
    ui->horizontalSlider->setRange(0, 100);
    ui->horizontalSlider->setValue(0);

    // 设置进度条样式
    QString qss = R"(
        QSlider::groove:horizontal {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                stop:0 #FF007F, stop:0.25 #FF00FF,
                stop:0.5 #00FFFF, stop:0.75 #00FF7F,
                stop:1 #00FF00);
            height: 15px;
            border-radius: 7px;
        }
        QSlider::sub-page:horizontal {
            background: rgba(255, 255, 255, 0.3);
            border-radius: 7px;
        }
        QSlider::handle:horizontal {
            background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5,
                fx:0.5, fy:0.5,
                stop:0 white, stop:0.5 #FFD700,
                stop:1 #FFA500);
            width: 25px;
            height: 25px;
            margin: -5px 0;
            border-radius: 12px;
            border: 2px solid #FFFFFF;
        }
    )";
    ui->horizontalSlider->setStyleSheet(qss);
}

Widget::~Widget()
{
    // 安全停止线程
    if (m_copyThread && m_copyThread->isRunning()) {
        qDebug() << "正在停止文件复制线程...";
        m_copyThread->requestInterruption();
        m_copyThread->wait(3000); // 最多等待3秒
        delete m_copyThread;
    }
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // 获取源文件路径
    QString filePath = QFileDialog::getOpenFileName(
        this,
        "选择要复制的文件",
        QDir::homePath(),
        "所有文件 (*.*)"
    );

    if (filePath.isEmpty()) {
        qDebug() << "用户取消文件选择";
        return;
    }

    QFileInfo fileInfo(filePath);
    QString destPath = m_targetDir + "/" + fileInfo.fileName();

    qDebug() << "目标文件路径:" << destPath;

    // 检查文件是否已存在
    if (QFile::exists(destPath)) {
        QMessageBox::warning(this, "警告", "目标文件已存在!");
        qWarning() << "目标文件已存在:" << destPath;
        return;
    }

    // 清理旧线程
    if (m_copyThread) {
        qDebug() << "终止之前的复制线程...";
        m_copyThread->requestInterruption();
        m_copyThread->wait();
        delete m_copyThread;
        m_copyThread = nullptr;
    }

    // 创建新线程
    m_copyThread = new mythread2(filePath, destPath, this);

    // 连接信号槽
    connect(m_copyThread, &mythread2::progressChanged,
            this, &Widget::updateProgress);
    connect(m_copyThread, &mythread2::copyFinished,
            this, &Widget::handleCopyResult);
    connect(m_copyThread, &QThread::finished,
            m_copyThread, &QObject::deleteLater);

    // 初始化UI状态
    ui->pushButton->setEnabled(false);
    ui->horizontalSlider->setValue(0); // 重置进度条
    ui->textEdit->append("开始复制文件: " + fileInfo.fileName());

    // 启动线程
    qDebug() << "启动文件复制线程...";
    m_copyThread->start();
}

void Widget::updateProgress(int value)
{
    // 确保在主线程更新UI
    Q_ASSERT(QThread::currentThread() == this->thread());

    // 限制更新频率(每5%更新一次)
    static int lastValue = -5;
    if (value - lastValue >= 5 || value == 100) {
        ui->horizontalSlider->setValue(value);
        lastValue = value;
        qDebug() << "当前进度:" << value << "%";
    }
}

void Widget::handleCopyResult(bool success, const QString &message)
{
    // 恢复按钮状态
    ui->pushButton->setEnabled(true);

    // 显示结果信息
    ui->textEdit->append(message);
    if (!success) {
        QMessageBox::critical(this, "错误", message);
        ui->horizontalSlider->setValue(0); // 失败时重置进度
    } else {
        ui->horizontalSlider->setValue(100); // 成功时显示100%
    }

    // 清理线程指针
    m_copyThread = nullptr;
    qDebug() << "文件复制操作完成,结果:" << message;
}


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

相关文章:

  • Redis 脚本:高效数据管理的利器
  • C++ list(双向链表)
  • 决策树(Decision Tree)基础知识
  • 网络安全可以从事什么工作?
  • 洛谷 P1480 A/B Problem(高精度详解)c++
  • 探索自适应学习在企业培训系统中的优势
  • 2025-03-06 学习记录--C/C++-C语言 函数参数传递的两种主要方法
  • NVIDIA Jetson Nano的国产替代,基于算能BM1684X+FPGA+AI算力盒子,支持deepseek边缘部署
  • 用Python分割并高效处理PDF大文件
  • Ubuntu 24.04 配置ODBC连接ORACLE 11G数据库
  • Java 大视界 -- 基于 Java 的大数据分布式任务调度系统设计与实现(117)
  • 力扣132. 分割回文串 II
  • js实现pdf文件路径预览和下载
  • Spring Boot使用JDBC /JPA访问达梦数据库
  • Dify部署踩坑指南(Windows+Mac)
  • 【C++】User-Defined Data Type
  • 文件操作(详细讲解)(2/2)
  • 【NL2SQL(text2sql) 到底准不准】智能BI中生成sql模块的评测数据构造 + 评测办法
  • go ent编写hooks时如何处理循环导入问题
  • 当服务器出现卡顿该怎么办?