目标:
- 主窗口不能假死
- 主窗口进度条必须能动
- 改写文件大小的单位(自适应)
-
界面尽可能美观
-
添加暂停功能
-
要在窗口显示文件信息
界面样式:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QLocale>
#include <QDateTime>
#include <cmath>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QString readPath; // 保存文件读取地址
QString writePath; // 保存文件存储地址
void printfFileInfo(); // 打印文件相关信息
MyThread *ct=NULL; // 线程
void copy(); // 拷贝函数
private slots:
void btnsClickedSlot(); // 按钮按下槽函数
void valueSlot(int); // 进度条设置
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->pushButtonOpen,SIGNAL(clicked()), // 连接按钮
this,SLOT(btnsClickedSlot()));
connect(ui->pushButtonSave,SIGNAL(clicked()),
this,SLOT(btnsClickedSlot()));
connect(ui->pushButtonCopy,SIGNAL(clicked()),
this,SLOT(btnsClickedSlot()));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::printfFileInfo() // 打印文件信息函数
{
QFileInfo info(readPath); // 创建文件信息类info,可以通过其成员函数获得文件相关信息
if(!info.exists()) // 存在为1,不存在为0,判断文件是否合法,不合法直接返回
{
return;
}
qint64 size = info.size(); // 获得文件大小,单位是字节
float sizek = static_cast<float>(size); // 数据类型转换
QLocale locale;
QString text; // 存储要打印的文件信息
if(size >= 1024 && size < pow(1024, 2)) // 文件大于1024,小于1024*1024字节,单位为MB
{
sizek = sizek / 1024;
text = locale.toString(sizek, 'f', 2); // 保留两位小数输出
text.prepend("文件大小:").append("KB");
}else if(size >= pow(1024,2) && size < pow(1024,3))
{
sizek = sizek / 1024 / 1024;
text = locale.toString(sizek, 'f', 2);
text.prepend("文件大小:").append("MB");
}else if(size >=pow(1024,3) && size < pow(1024,4))
{
sizek = sizek / 1024 / 1024 / 1024;
text = locale.toString(sizek, 'f', 2);
text.prepend("文件大小:").append("GB");
}else if(size < 1024)
{
text = QString::number(size);
text.prepend("文件大小:").append("B");
}
ui->textBrowserOpen->append(text);
text = info.baseName(); // 获得文件名字
text.prepend("文件名字");
ui->textBrowserOpen->append(text); // 在ui上显示
// 获得最后修改时间
text = info.lastModified().toString("修改时间:yyyy-MM-dd hh:mm:ss");
ui->textBrowserOpen->append(text);
bool result = info.isReadable(); // 文件可读性
if(result)
ui->textBrowserOpen->append("文件可读");
else
ui->textBrowserOpen->append("文件不可读");
}
void Dialog::copy() // 复制函数
{
if(ui->pushButtonCopy->text() == "开始复制") // 当按钮上显示“开始复制时”
{
if(readPath == "") // 没有选择文件打开时,跳出消息对话框进行提示
{
QMessageBox::warning(this,"提示","请选择要读取的文件!");
return;
}
else if(writePath == "") // 没有选择文件保存地址时,跳出提示
{
QMessageBox::warning(this,"提示","请选择要保存的文件地址!");
return;
}
// 当下载进度为100%时,删除线程,为重新下载做准备
if(ui->progressBar->value() == 100)
{
ct = NULL;
}
if(ct == NULL) // 当线程没有被创建时进入
{
// 创建子线程,在子线程中进行比较耗时的操作,即拷贝文件
// 创建时将已打开的文件路径及要保存的文件路径传递过去
ct = new MyThread(readPath,writePath,this);
// 连接两个线程通信的信号槽,使progressBar->value的值能够实时更新
connect(ct,SIGNAL(valueSignal(int)),this,SLOT(valueSlot(int)));
// 设置run状态,开始复制
ct->setRunningState(true);
// 线程启动
ct->start();
}
else // 当线程已被创建时进入
{
ct->setRunningState(true);
}
ui->pushButtonCopy->setText("停止复制"); // 点击开始复制后,按钮变为停止复制
}
// 若按下时为停止复制(暂停)
else if(ui->pushButtonCopy->text() == "停止复制")
{
ct->setRunningState(false); // 停止复制
ui->pushButtonCopy->setText("开始复制"); // 按钮变为开始复制
}
}
void Dialog::btnsClickedSlot() // 按钮点击槽函数
{
if(ui->pushButtonOpen == sender()) // 如果点击的按钮是打开文件按钮
{
// 文件格式过滤器
QString filter = "所有文件(*);;Qt(*.c *.cpp *.ui)";
// 保存文件地址
QString path = QFileDialog::getOpenFileName(this,"打开","D:/",filter);
if(path != "") // 选择文件后进入
{
ui->textBrowserOpen->append(path); // 在窗口打印路径信息
readPath = path;
printfFileInfo(); // 调用打印信息函数
}else if(readPath == "") // 为选择文件进入
{
QMessageBox::warning(this,"注意","请选择要打开的文件");
}
}else if(ui->pushButtonSave == sender()) // 按下保存按钮时进入
{
QString filter = "所有文件(*);;Qt(*.c *.cpp *.ui)";
QString path = QFileDialog::getSaveFileName(this,"保存","D:/",filter);
if(path != "")
{
ui->textBrowserSave->append(path);
writePath = path;
}else if(writePath == "")
{
QMessageBox::warning(this,"注意","请选择要保存的地址");
return;
}
}else if(ui->pushButtonCopy == sender()) // 按下复制按钮时进入,开始拷贝
{
copy();
}
}
void Dialog::valueSlot(int value) // 接受value值槽函数
{
ui->progressBar->setValue(value); // 设置value值
if(value == 100)
{
// 释放按钮
ui->pushButtonCopy->setEnabled(true);
// 异步刷新
this->hide();// 隐藏主窗口,只是看不到
this->show();// 显示主窗口
QMessageBox::information(this,"通知","文件拷贝完毕");
}
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QFile>
#include <QDateTime>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QString,QString,QObject *parent = 0); // 注意修改构造函数参数
~MyThread();
bool getRunningState() const;
void setRunningState(bool value);
signals:
void valueSignal(int);
protected:
void run();
private:
bool runningState;
QString readPath;
QString writePath;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
// 注意修改参数
MyThread::MyThread(QString readPath,QString writePath,QObject *parent) : QThread(parent)
{
this->readPath = readPath;
this->writePath = writePath;
}
MyThread::~MyThread()
{
}
void MyThread::run()
{
// 创建QFile对象
QFile readFile(readPath);
QFile writeFile(writePath);
// 打开文件流
readFile.open(QIODevice::ReadOnly);
writeFile.open(QIODevice::WriteOnly);
// 获取文件总大小
qint64 totalSize = readFile.size();
// 已经读写的大小
qint64 hasRead = 0;
// 字节数组类
QByteArray buffer;
while(!readFile.atEnd()) // 判断是否位于文件尾部
{
// 当标志位为false时进入暂停延时,为true时跳出继续读写
while(!runningState)
{
msleep(100);
}
// 读取数据
buffer = readFile.read(1024);
// 写出数据
hasRead += writeFile.write(buffer);
// 算百分比
int per = 100 * hasRead/totalSize;
// 设置给进度条
emit valueSignal(per);
}
}
bool MyThread::getRunningState() const
{
return runningState;
}
void MyThread::setRunningState(bool value)
{
runningState = value;
}