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;
}