Обновление QProgressbar из другого потока

Я разработал свой собственный гибридный потоковый шифр, а для графического интерфейса использую Qt. Первоначально я писал его в одном потоке, но из-за потокового шифра графический интерфейс не работал при работе с большими файлами. Поэтому я перенес шифрование / дешифрование на отдельный Qthread. Также, чтобы показать прогресс, я включил в графический интерфейс стандартную панель QProgressbar. Но когда я запускаю файловый ввод-вывод, шифрование / дешифрование работает отлично, но индикатор выполнения не обновляется должным образом. После завершения всей операции индикатор выполнения внезапно переходит от 0% до 100%, показывая, что у него не было возможности обновить во время операции. Для кода я отправил завершенный процент из FileCrypto в основной поток графического интерфейса пользователя в слот QProgressbar setValue (int). Поскольку это не сработало, я также попытался отправить int poitner в поток FileCrypto, обновляя указатель с процентом и используя QTimer в потоке графического интерфейса, чтобы локально проверить значение 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... :'(");
}

Вот как я создаю поток и подключаю его к основному потоку графического интерфейса:

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()));

Если я не обновляю индикатор выполнения, т.е. не показываю процентное значение, процесс происходит намного быстрее. Я также пробовал печатать проценты. Он чертовски тормозит, но значения в порядке. Также вы можете предложить способ изменить его на буферизованный ввод-вывод ....

Здесь очень ценится любая помощь .......


person Rahul De    schedule 02.07.2012    source источник
comment
Слоты IIRC Qt синхронны. См. stackoverflow.com/questions/1264887/ и даже лучше cdumez.blogspot.de/2011/03/   -  person RedX    schedule 02.07.2012
comment
обычным способом ... после вышеуказанных подключений fc- ›start (); Это оно...   -  person Rahul De    schedule 02.07.2012
comment
У вас есть вызов moveToThread() в конструкторе FileCrypto?   -  person Chris    schedule 02.07.2012


Ответы (1)


Проблема не в том, что вы звоните из другого потока. Это находится в:

emit completed(int((done / length) * 100));

Поскольку done и length являются типами int, а done <= length, done/length == 0. Так что измените его на:

emit completed(100 * done / length);

(это может привести к арифметическому переполнению).

person KCiebiera    schedule 02.07.2012
comment
Кто-нибудь должен изменить постановку задачи :) - person KCiebiera; 02.07.2012