Обновление QProgressbar из другого потока
Я разработал свой собственный гибридный потоковый шифр и для графического интерфейса я использую Qt. Первоначально я написал его в одном потоке, но, будучи потоковым шифром, GUI не работал при работе с большими файлами. Поэтому я перенес шифрование / дешифрование на отдельный Qthread. Также, чтобы показать прогресс, я включил в QI стандартный QProgressbar. Но когда я запускаю File I/O, шифрование / дешифрование работает отлично, но индикатор выполнения не обновляется должным образом. После завершения всей операции индикатор выполнения внезапно падает с 0% до 100%, показывая, что у него не было возможности обновить во время операции. Для кода я отправил заполненный процент из FileCrypto в основной поток GUI на слот setProction (int) QProgressbar. Так как это не сработало, я также попытался отправить int poitner в поток FileCrypto, обновив указатель в процентах и используя QTimer в потоке GUI, чтобы локально проверить значение int и обновить индикатор выполнения, но все же Я получил точно такой же результат.
Вот мой код:
Класс FileCrypto:
#include <QThread>
#include <QFile>
#include <PolyVernam.h> //my algo header
class FileCrypto : public QThread
{
Q_OBJECT
public:
FileCrypto(QString, QString, int);
bool stopIt;
protected:
void run();
signals:
void completed(int);
void msg(QString);
void pathMsg1(QString);
void pathMsg2(QString);
void keyMsg(QString);
private:
QFile src, dest;
QString tag;
int mode;
qint64 length;
PolyVernam pv;
};
Код:
#include <FileCrypto.h>
FileCrypto::FileCrypto(QString input, QString keyFile, int mode)
{
stopIt = false;
this->mode = mode;
src.setFileName(input);
if(mode == 1)
{
emit msg("Current Encryption/Decryption status: Encrypting file... :D:D");
tag = "-encrypted";
pv.setMode("encrypt", "");
}
else
{
emit msg("Current Encryption/Decryption status: Decrypting file... :D:D");
tag = "-decrypted";
pv.setMode("decrypt", keyFile);
}
dest.setFileName(QFileInfo(src).absolutePath() + "/" + QFileInfo(src).baseName()
+ tag + "." + QFileInfo(src).completeSuffix());
length = src.bytesAvailable();
}
void FileCrypto::run()
{
qint64 done = 0;
quint8 r, outChar;
char ch;
QDataStream in(&src);
in.setVersion(QDataStream::Qt_4_7);
src.open(QIODevice::ReadOnly);
QDataStream out(&dest);
out.setVersion(QDataStream::Qt_4_7);
dest.open(QIODevice::WriteOnly);
while(!in.atEnd() && !stopIt)
{
done++;
in >> r;
ch = char(r);
if(mode == 1)
outChar = pv.encrypt(QString(ch)).at(0).toAscii();
else
outChar = pv.decrypt(QString(ch)).at(0).toAscii();
out << outChar;
emit completed(int((done / length) * 100));
}
src.close();
dest.close();
if(stopIt)
this->exit(0);
if(mode == 1)
{
emit pathMsg1(QFileInfo(src).absoluteFilePath());
emit pathMsg2(QFileInfo(dest).absoluteFilePath());
}
else
{
emit pathMsg1(QFileInfo(dest).absoluteFilePath());
emit pathMsg2(QFileInfo(src).absoluteFilePath());
}
emit keyMsg(pv.keyFilePath);
emit msg("Current Encryption/Decryption status: Idle... :'(");
}
Вот как я делаю поток и подключаю его к основному потоку GUI:
FileCrypto *fc = new FileCrypto(ui->lineEdit_4->text(), "", 1);
connect(fc, SIGNAL(completed(int)), ui->progressBar, SLOT(setValue(int)));
connect(fc, SIGNAL(msg(QString)), ui->statusBar, SLOT(showMessage(QString)));
connect(fc, SIGNAL(pathMsg1(QString)), ui->lineEdit_4, SLOT(setText(QString)));
connect(fc, SIGNAL(pathMsg2(QString)), ui->lineEdit_5, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), ui->lineEdit_2, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), this, SLOT(done()));
Если я не обновляю индикатор выполнения, т.е. не выдает процент, процесс происходит намного быстрее. Я также попытался напечатать процент. Это замедляет его как ад, но значения в порядке. Также можете ли вы предложить способ изменить его на буферизованный ввод-вывод....
Любая помощь очень ценится здесь.......
1 ответ
Проблема не в том, что вы звоните из другого потока. Это находится в:
emit completed(int((done / length) * 100));
поскольку done
а также length
являются типами in t, и done <= length
, done/length == 0
, Так что измените его на:
emit completed(100 * done / length);
(если может привести к арифметическому переполнению).