Solved QFile copy multiple files progress bar
-
I copy a bunch of files from one location to another. File paths are stored in
QStringlist
and I iterate over list using for loop and copy files usingQFile::copy
. I want to have some kind of progress bar but when I tried to implement one but it didn't refresh. The gui locked up and only refreshed after all files were copied.
Is there a way to prevent gui from locking up so progress bar can refresh? -
Hi
The quick hax is to call QApplication::processEvents()
http://www.informit.com/articles/article.aspx?p=1405544&seqNum=3A more solid way is to use a worker thread and signal to it pr file and
update the progressbar. As far as i know QFile can be used in another thread. -
@Eligijus
Do you intend a progressbar which shows progress through how many files have been copied (i.e. just updated a fixed amount after each file copy completed), or which updates during each file's copy progress (e.g. based on total number of bytes copied)? This will be relevant for whatever solution. -
@JNBarchan shows progress of how many files have been copied. I.e. I have 100 files and progress bar will go from 1 to 100 incrementing by 1 after a file has been successfully copied.
-
@Eligijus
So you only need to update progressbar outside of anyQFile::copy
, in between each call, which makes it much simpler. Show us your attempt "but when I tried to implement one but it didn't refresh"? In some shape or form, it's not getting refreshed while you keep doing copy code, the UI isn't getting any update time till afterwards.... -
@JNBarchan I'm updating progressbar in qml
for (var i = 0; i < files.length; ++i) { progressBar.value = i manager.copy(sourcePath + files[i],destPath + files[i]) }
I can't provide c++ widget version at the moment I'll have to write something up.
But I guess @mrjj answer is valid here. I either have to call processEvents or move copying to another thread. -
@Eligijus
Yep that should make it update pr file.
Make sure to read link about blocking user input so its not possible to choose exit while copying. -
This is the solution I came up with. Maybe someone will find it useful.
class Copier : public QThread { Q_OBJECT Q_PROPERTY(double minimum READ minimum NOTIFY minimumChanged) Q_PROPERTY(double maximum READ maximum NOTIFY maximumChanged) Q_PROPERTY(double progress READ progress NOTIFY progressChanged) public: Copier(QObject *parent = nullptr); Q_INVOKABLE void copy(const QString &sourceFolder, const QString &destFolder); double minimum() const; double maximum() const; double progress() const; signals: void minimumChanged(double minimum); void maximumChanged(double maximum); void progressChanged(double value); private: QStringList getFolderContents(const QString &sourceFolder) const; qint64 fileSize(const QString &sourceFolder, const QStringList &fileList); void copyFiles(); virtual void run() Q_DECL_OVERRIDE; QString mSourceFolder; QString mDestFolder; QStringList mFileList; double mMinimum; double mMaximum; double mProgress; };
Copier::Copier(QObject *parent) : QThread(parent), mMinimum(0), mMaximum(0), mProgress(0) { } void Copier::copy(const QString &sourceFolder, const QString &destFolder) { mSourceFolder = sourceFolder; mDestFolder = destFolder; mFileList = getFolderContents(sourceFolder); mMinimum = 0; mMaximum = fileSize(sourceFolder, mFileList); emit minimumChanged(mMinimum); emit maximumChanged(mMaximum); if (!isRunning()) start(); } double Copier::minimum() const { return mMinimum; } double Copier::maximum() const { return mMaximum; } double Copier::progress() const { return mProgress; } QStringList Copier::getFolderContents(const QString &sourceFolder) const { QStringList fileList; std::function<bool(const QString&, const QString&)> folderContents; folderContents = [&](const QString &sourceFolder, const QString &destFolder)->bool { QDir sourceDir(sourceFolder); if (!sourceDir.exists()) return false; foreach (const QFileInfo &fileInfo, sourceDir.entryInfoList(QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Dirs | QDir::Files)) { QString srcFilePath = fileInfo.filePath(); QString dstFilePath = destFolder.isEmpty() ? fileInfo.fileName() : destFolder + QDir::separator() + fileInfo.fileName(); if (fileInfo.isDir()) { if (!folderContents(srcFilePath, dstFilePath)) return false; } else { fileList.append(dstFilePath); } } return true; }; if (folderContents(sourceFolder, QString())) return fileList; else return QStringList(); } qint64 Copier::fileSize(const QString &sourceFolder, const QStringList &fileList) { qint64 total = 0; foreach (const QString &fileName, fileList) total += QFile(sourceFolder + QDir::separator() + fileName).size(); return total; } void Copier::copyFiles() { qint64 bufferSize = 4194304; QByteArray buffer; mProgress = 0; emit progressChanged(mProgress); foreach (const QString &fileName, mFileList) { QString srcFilePath = mSourceFolder + QDir::separator() + fileName; QString dstFilePath = mDestFolder + QDir::separator() + fileName; QFile srcFile(srcFilePath); QFile dstFile(dstFilePath); QFileInfo dst(dstFilePath); QDir dir = dst.dir(); if (!dst.isDir() && !dir.exists()) dir.mkpath(dir.path()); if (srcFile.open(QIODevice::ReadOnly) && dstFile.open(QIODevice::WriteOnly)) { qint64 internalBufferSize = srcFile.size() < bufferSize ? srcFile.size() : bufferSize; while (1) { buffer = srcFile.read(internalBufferSize); if (buffer.isEmpty()) break; dstFile.write(buffer); mProgress += internalBufferSize; emit progressChanged(mProgress); } srcFile.close(); dstFile.close(); } } } void Copier::run() { copyFiles(); }
Window { visible: true width: 640 height: 480 title: qsTr("Hello World") ProgressBar { id: control x: 50 y: 50 width: 400 height: 100 padding: 2 from: copier.minimum to: copier.maximum value: copier.progress background: Rectangle { color: "black" } contentItem: Item { Rectangle { width: control.visualPosition * parent.width height: parent.height color: "red" } } } Copier { id: copier } Button { anchors.top: control.bottom anchors.topMargin: 50 anchors.right: control.right text: "copy" onClicked: { copier.copy("/home/eligijus/BigDisk/testArea/testArea", "/media/eligijus/usb") } } }
-
Hi All,
I have used Qt 5.7.1 , i have created GUI application in that one of the screen having file copy . When clicked that button file will be copy from source to destination with progress bar , So how to create this please give me any suggestion
Thanks,
RYS -
Hi and welcome.
For a fast solution, simply use QFile
QFile::copy("/path/file", "/path/copy-of-file");Progressbar is not possible.
If you really want progressbar that can update while copying, you must write your own file copy function.
https://stackoverflow.com/questions/10195343/copy-a-file-in-a-sane-safe-and-efficient-way
-
@mrjj said in QFile copy multiple files progress bar:
Hi and welcome.
For a fast solution, simply use QFile
QFile::copy("/path/file", "/path/copy-of-file");Progressbar is not .
If you really want progressbar that can update while copying, you must write your own file copy function.
https://stackoverflow.com/questions/10195343/copy-a-file-in-a-sane-safe-and-efficient-way
Hi,
is Progressbar possible ? if
Qfile *FsCopy = new Qfile;
FsCopy.copy("/path/file", "/path/copy-of-file"); -