練習1:Qt 進度條與多線程應用
題目描述
開發一個基于 Qt 的應用程序,該應用程序包含一個水平進度條(
QSlider
),并且需要通過多線程來更新進度條的值。請根據以下要求完成代碼:
界面設計:
使用?
QSlider
?控件作為進度條。設置?
QSlider
?的樣式多線程更新:
創建一個自定義線程類?
mythread
,該線程類繼承自?QThread
。使主線程接收到信號后,更新?
QSlider
?的值。信號與槽:
使用信號與槽機制實現線程與主線程之間的通信。
當線程中的值發生變化時,通過信號通知主線程更新進度條。
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_NAMESPACEclass 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 的文件復制工具,要求實現以下功能:
文件選擇:
使用?
QFileDialog
?選擇源文件和目標文件。支持選擇大文件(超過 800MB)。
文件復制:
使用 Qt 的文件 IO 操作(
QFile
)實現文件復制功能。支持分塊讀取和寫入文件,避免一次性加載大文件到內存中。
多線程處理:
使用?
QThread
?在后臺執行文件復制操作,避免阻塞主線程。通過信號與槽機制,將復制進度實時傳遞給主線程。
進度顯示:
使用自定義的?
QSlider
?作為進度條,顯示文件復制的進度。自定義?
QSlider
?的樣式,使其外觀美觀。錯誤處理:
如果文件打開失敗或復制失敗,彈出錯誤提示框。
如果復制完成,彈出提示框顯示“文件復制完成”。
1.mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include <QString>class MyThread : public QThread
{Q_OBJECTpublic: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_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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, "完成", "文件復制完成");}
}