Reputation: 397
I wrote a C++/QT Application with "Installer" features. Everything workes fine, but when I click outside the window while my programm is in a "copy process", it somehow loses focus and freezes until the copy process is over, then everything is displayed normaly with a QProgressBar value of 100%.
Im copying like this:
void Installer_C::copy(QString aSrcPath, QString aDstPath)
{
//handles
hSrc = CreateFileW(..); //source file
hDst = CreateFileW(..); //destination
//copy
ReadFile(...);
LockFile(...);
WriteFile(...); //->returnes bytesWritten
UnlockFile(...);
updateQProgressBar(bytesWritten); //updates progressbar in my application
CloseHandle(...);
}
This function is called in a foreach loop iterating through a QStringList with files (located in my launchInstall() function).
Due to my problems, I thought about creating Threads for this copy process. Is it more efficient to create a new thread for each Installer_C::copy()
call, or to just create one Thread to call the launchInstall()
function (I think it wouldn't help much).
Or a better Question: Would it even solve my problem that the application freezes? And how shall I do it so that the ProgressBar still will be updated from this thread?
Upvotes: 0
Views: 783
Reputation: 1412
As I know there are two possible ways to solve this problem in Qt:
QCoreApplication::processEvents()
. As docs said it's not a bad solution and suitable for handling long operations. I think it could be usefull for you. For example, you could call it after copying each file (or couple of files).So my suggestion is: if you need easy and quick working solution, the first way is for you.
If you want to make well-designed and more complex application and you are ready to code little bit more, use the second approach.
Upvotes: 0
Reputation: 1420
I think, the best way to solve your problem is to create one addition thread to copy process. You can use QThread (Qt documentation: QThread) class to create a thread, which will copy files. The main thread will execute your GUI and it will be available during files copying.
Small example for copying thread:
class CopyThread : public QThread
{
Q_OBJECT
private:
QStringList oldfiles_;
QStringList newfiles_;
public:
CopyThread(const QStringList& oldfiles,
const QStringList& newfiles,
QObject * parent = 0)
: QThread(parent)
, oldfiles_(oldfiles)
, newfiles_(newfiles)
{}
void run() Q_DECL_OVERRIDE
{
int min = qMin(oldfiles_.count(), newFiles.count());
for(int i=0; i<min; ++i)
{
copyFile(oldfiles_.at(i), newFiles_.at(i));
emit signalCopyFile(oldfiles_.at(i), newFiles_.at(i));
}
}
signals:
void signalCopyFile(const QString&, const QString&);
private:
void copyFile(QString aSrcPath, QString aDstPath)
{
QFile::copy(aSrcPath, aDstPath);
}
};
Of course, you must implement slot on your widget for signalCopyFile(const QString&, const QString&)
and make connection. Small piece of code (for example) to start copy thread and make connection:
QStringList oldFiles;
oldfiles.append("C:/1.txt");
QStringList newFiles;
newFiles.append("C:/2.txt");
yourProgressBar.setMaximum(oldFiles.count());
yourProgressBar.setMinimum(0);
yourProgressBar.setValue(0);
CopyThread *copyThread = new CopyThread(oldFiles, newFiles, this);
connect(copyThread, &CopyThread::finished, copyThread, &QObject::deleteLater);
connect(copyThread, &CopyThread::signalCopyFile, youWidget, &YouWidget::yourSlot);
copyThread->start();
In yourSlot
you can update value of your QProgressBar
:
void yourSlot(const QString& oldFile, const QString& newFile)
{
// your actions when one file was copied
yourProgressBar->setValue(yourProgressBar.value() + 1);
}
Everything will be all right without freezes!
Upvotes: 1