Многопоточность в Qt4 (Загрузка данных из файла и QProgressBar)

Модератор: Модераторы разделов

Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Многопоточность в Qt4

Сообщение Assuri »

Здраствуйте.

Возникла проблема: решил я сделать так, чтобы во время загрузки данных из файла, отображался QProgressBar. Просто так, это не сделать, так как понадобится несколько потоков :( Отсюда вытекают непонятные вещи.

Я создал заголовочный файл:

Код: Выделить всё

#include <QThread>

class QProgressBar;

class ProgressBar : public QThread
{
    public:
        ProgressBar(QWidget* parent = 0);
        void stop();
        QProgressBar* pb;
        void setMax(int);
        void setValue(int);
    protected:
        void run();
    private:
        volatile bool isStopped;
};

Затем описал функции:

Код:

#include <QtGui> #include "progressbar.h" ProgressBar::ProgressBar(QWidget *parent) { isStopped = false; pb = new QProgressBar(parent); } void ProgressBar::setMax(int max) { pb->setRange(0,max); } void ProgressBar::setValue(int value) { pb->setValue(value); } void ProgressBar::run() { if ( !isStopped ) pb->show(); isStopped = false; } void ProgressBar::stop() { pb->hide(); isStopped = true; }

И в конце концов, решил его применить:

Код:

if ( !progressBar ) progressBar = new ProgressBar; // Считается кол-во строк progressBar->setMax(rows); progressBar->start(); rows = 0; while ( !stream.atEnd() ) { tempString = stream.readLine(); rows++; progressBar->setValue(rows); } progressBar->stop();

Однако вот какой результат, при выполнении программы:
QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread
QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread
QObject::startTimer: timers cannot be started from another thread
QObject::startTimer: timers cannot be started from another thread

Как исправлять?
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

Скажите, хотя бы, что эти ошибки означают? Потому что я сколько бы не переписывал код ошибка одна и та же.

Ошибку я нашел, ругается на:

Код: Выделить всё

void ProgressBar::run()
{
    while ( currentValue < maximum )
    {
          progressDialog->show(); // << вот на это
    }
    currentValue = 0;
}

И что, мне надо и для QProgressDialog создавать свой поток?
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

Сделал все чуток по другому:
mainwidget.h

Код: Выделить всё

ThreadProgressBar threadProgressBar;
QProgressDialog *pb;

mainwidget.cpp

Код:

if ( !pb ) { pb = new QProgressDialog; connect(&threadProgressBar,SIGNAL(changeValue(int)),pb,SLOT(setValue(int)),Qt::Queued Connection); } pb->setMaximum(rows); pb->show(); threadProgressBar.setMaximum(rows); threadProgressBar.start(); rows = 0; stream.seek(0); while ( !stream.atEnd() ) { tempString = stream.readLine(); rows++; threadProgressBar.setValue(rows); } threadProgressBar.stop(); pb->hide();

threadprogressbar.h

Код:

class ThreadProgressBar : public QThread { Q_OBJECT signals: void changeValue(int); public: ThreadProgressBar(); void setMaximum(int max); void setValue(int value); void stop(); protected: void run(); private: int maximum; int currentValue; bool stopped; };

threadprogressbar.cpp

Код:

ThreadProgressBar::ThreadProgressBar() { currentValue = 0; maximum = 0; stopped = false; } void ThreadProgressBar::setMaximum(int max) { maximum = max; } void ThreadProgressBar::run() { while ( !stopped ) emit changeValue(currentValue); stopped = false; currentValue = 0; } void ThreadProgressBar::setValue(int value) { if ( value <= maximum ) { stopped = false; currentValue = value; } else stopped = true; } void ThreadProgressBar::stop() { stopped = false; currentValue = 0; }

Ну вот что опять не так!
Ошибка только такая:
QFont: It is not safe to use text and fonts outside the GUI thread
QFont: It is not safe to use text and fonts outside the GUI thread

Но прогрессдиалога все равно не видно :(
Спасибо сказали:
Аватара пользователя
panter_dsd
Сообщения: 157
Статус: Жаждущий знаний
ОС: Slackware 12

Re: Многопоточность в Qt4

Сообщение panter_dsd »

Так есть ведь штатный QProgressDialog...
Делаете так

Код: Выделить всё

QProgressDialog progress(tr("Loading wait..."), tr("No"),min_value,max_value , this);
progress.setWindowModality(Qt::WindowModal);
while (!FileStream.atEnd())
{
    progress.setValue(progress.value()+1);
    QCoreApplication::processEvents();// Это обязательно
//Reading
}
progress.setMaximum(max_value);

min_value - минимальное значение
max_value - максимальное значение

С уважением.
Пантер.
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

panter_dsd писал(а):
05.11.2007 11:18
Так есть ведь штатный QProgressDialog...
Делаете так

Код: Выделить всё

QProgressDialog progress(tr("Loading wait..."), tr("No"),min_value,max_value , this);
progress.setWindowModality(Qt::WindowModal);
while (!FileStream.atEnd())
{
    progress.setValue(progress.value()+1);
    QCoreApplication::processEvents();// Это обязательно
//Reading
}
progress.setMaximum(max_value);

min_value - минимальное значение
max_value - максимальное значение

Вы гений! Обшарил Google и нигде такого подхода не видел! Огромное вам спасибо! Только у меня к вам такая просьба: можете объяснить этот код? Как он работает?
Спасибо сказали:
Аватара пользователя
panter_dsd
Сообщения: 157
Статус: Жаждущий знаний
ОС: Slackware 12

Re: Многопоточность в Qt4

Сообщение panter_dsd »

Легко:
QProgressDialog progress(tr("Loading wait..."), tr("No"),min_value,max_value , this);
Это создание QProgressDialog, параметры:
1. Надпись в диалоге
2. Надпись на кнопке прерывания
3. Минимальное значение
4. Максимальное значение
5. Родитель
progress.setWindowModality(Qt::WindowModal);
Делаем данный диалог модальным
progress.setValue(progress.value()+1);
Увеличиваем значение на 1, можно просто присваивать значение, т.е. progress.setValue(value);
QCoreApplication::processEvents();// Это обязательно
Вот это самое главное - выборка очереди сигналов, без этой строчки приложение будет как бы висеть и диалог никогда не появится.
progress.setMaximum(max_value);
Присваиваем QProgressDialog максимальное значение, после этого он сам исчезает.

Почаще заглядывайте в ассистента. :)

С уважением.
Пантер.
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

panter_dsd писал(а):
05.11.2007 12:05
Почаще заглядывайте в ассистента. :)

У меня он всегда открыт ;) А где бы это я мог найти в нем?
Спасибо сказали:
Аватара пользователя
panter_dsd
Сообщения: 157
Статус: Жаждущий знаний
ОС: Slackware 12

Re: Многопоточность в Qt4

Сообщение panter_dsd »

В разделе QProgressDoalog. :)
А вообще там стандартных диалогов туева хуча, даже экзампл есть с диалогами.

С уважением.
Пантер.
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

panter_dsd писал(а):
05.11.2007 12:26
В разделе QProgressDoalog. :)
А вообще там стандартных диалогов туева хуча, даже экзампл есть с диалогами.

Понятно.

Проблема решена.
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

Одно помешало другому. Вот такая у меня ситуация: мне надо скрыть прогресс бар и прекратить выполнение цикла, после нажатия кнопки "Cancel". Код:

Код:

// main function: if ( !pb ) { pb = new QProgressDialog(tr("Please, wait while data is loading to SQL database.."), tr("Cancel"),0,1, this); connect(pb,SIGNAL(canceled()),this,SLOT(cancelLoading())); } pbValue = 0; pb->setRange(0,rows); streamData->seek(0); QCoreApplication::processEvents(); while ( !streamData->atEnd() ) { tempString = streamData->readLine(); pbValue++; pb->setValue(pbValue); } pb->hide(); void MainWidget::cancelLoading() { int r = QMessageBox::warning(this,tr("Cancel of Loading"),tr("Are you sure, that you want\nto stop the loading?"),QMessageBox::Yes | QMessageBox::Default,QMessageBox::No | QMessageBox::Escape); if ( r == QMessageBox::No ) { pb->setValue(pbValue); return; } pb->hide(); streamData->seek(pb->maximum()); QFile databaseFile(name); databaseFile.remove(); }

Однако, последние 4 строки функции cancelLoadion просто напросто игнорируются. Я так понимаю, что это из-за QCoreApplication::processEvents()... Как быть?
Спасибо сказали:
Аватара пользователя
Red Gremlin
Сообщения: 512
Статус: самоучка
ОС: Rosa 2016 Fresh

Re: Многопоточность в Qt4

Сообщение Red Gremlin »

Все дело в return
"В мире есть случайность, есть предопределенность и есть то, что ты планируешь совершить."
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

Red Gremlin писал(а):
08.11.2007 14:32
Все дело в return

Что это с ним не так? Убрал его и поставил else - результат тот же.
Спасибо сказали:
Аватара пользователя
Red Gremlin
Сообщения: 512
Статус: самоучка
ОС: Rosa 2016 Fresh

Re: Многопоточность в Qt4

Сообщение Red Gremlin »

Извиняюсь, не туда посмотрел
"В мире есть случайность, есть предопределенность и есть то, что ты планируешь совершить."
Спасибо сказали:
Аватара пользователя
panter_dsd
Сообщения: 157
Статус: Жаждущий знаний
ОС: Slackware 12

Re: Многопоточность в Qt4

Сообщение panter_dsd »

А сама мессага появляется? Что происходит если в ней нажать Yes? Что если нажать No? Распишите поподробнее что происходит.

С уважением.
Пантер.
Спасибо сказали:
Аватара пользователя
Assuri
Сообщения: 678
Статус: #include <brain.h>
ОС: Fedora 12

Re: Многопоточность в Qt4

Сообщение Assuri »

Ну я в принципе нашел как "вывернуться". Создал булевскую переменную wasCenceled. Затем в цикле while сделал условие, что мол пока wasCanceled == false читаем файл, а когда wasCanceled = true, цикл прекращается. wasCanceled менялся в слоте, который имитировался нажатием кнопки "Cacnel".
Спасибо сказали: