Russian Qt Forum
Ноябрь 25, 2024, 07:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Изменить значение прогрессбара диалогового окна из дочернего потока  (Прочитано 8301 раз)
neosapient
Гость
« : Июль 22, 2008, 19:04 »

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

Пишу следующую программку:
 - есть главное диалоговое окно, для ввода переменных
 - есть дочерний поток (класс-наследник QThread), который запускается при нажатии на кнопку и крутиться в цикле пока всё не посчитается

Расчет долгий, и я хотел бы отобразить в прогресс баре пройденый этап расчета.

Сначала попробовал вызывать методы ProgressBar::setMinimum, ProgressBar::setMaximum и ProgressBar::setValue из дочернего потока.
Но в ответ получал крах программы, так как надо рисовать в главном (GUI) потоке.

Тогда я попробовал создать сигналы у класса-наследника QThread, но компилятор ругается:
"Error: Signals cannot have access specifier"

Как решить такой "типовой" пример? Может есть готовый пример - хотел бы изучить, а не изобретать велосипед.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #1 : Июль 22, 2008, 19:30 »

Вариантов решиния два:
1) Как вы и делали, через сигналы. Все должно работать. Код в студию.
2) Посредством событий. Посылаете событие из дочернего потока и ловите его в главном потоке.

ЗЫ: Подобные темы уже нераз подымались на форуме
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
spirit
Гость
« Ответ #2 : Июль 22, 2008, 19:50 »

Код:
class AnotherThread: public QThread
{
    Q_OBJECT

signals:
    void valueChanged(int);

public:
    AnotherThread(QObject *parent, int val)
        : QThread(parent),
        m_currentVal(val)
    {
    }

protected:
    virtual void run() { 
        for (int i = 0; i < m_currentVal; ++i)
            emit valueChanged(i);
    }

private:
    int m_currentVal;
};

class MainWindow:public QMainWindow
{
    Q_OBJECT

public:
    MainWindow::MainWindow(QWidget *parent = 0)
        : QMainWindow(parent)
    {
        QHBoxLayout *mainLayout = new QHBoxLayout();

        m_pbProgress = new QProgressBar();
        m_pbProgress->setMinimum(0);
        m_pbProgress->setMaximum(100);

        m_at = new AnotherThread(this, m_pbProgress->maximum());
        connect(m_at, SIGNAL(valueChanged(int)), m_pbProgress, SLOT(setValue(int)));

        QPushButton *pbRun = new QPushButton("Run");
        connect(pbRun, SIGNAL(clicked()), m_at, SLOT(start()));

        mainLayout->addWidget(m_pbProgress);
        mainLayout->addWidget(pbRun);

        QWidget *central = new QWidget();
        central->setLayout(mainLayout);
        setCentralWidget(central);
    }

private:
    QProgressBar *m_pbProgress;
    AnotherThread *m_at;
};

« Последнее редактирование: Июль 22, 2008, 20:18 от spirit » Записан
ритт
Гость
« Ответ #3 : Июль 23, 2008, 00:15 »

мля...я читаю код и них не могу врубиться что там могло не работать и материться на сигнал...
а это, по-ходу, код-как-делать-надо Улыбающийся
жук ты, спирит, хоть бы строчку чиркнул )
Записан
Alex03
Гость
« Ответ #4 : Июль 23, 2008, 06:50 »

Надеюсь Qt 4.x.x?

Во первых Ваш код компилируется и даже как-то работает, НО...

С завидным постоянством на форуме возникают вопросы связнные с QThread. Народ не хочет читать документацию и постоянно наступает на грабли.

В Qt 4.x.x у каждого объекта есть принадлежность к потоку. В Вашем случае и m_at и m_pbProgress "принадлежат" к главному потоку. Соответственно
Код:
connect(m_at, SIGNAL(valueChanged(int)), m_pbProgress, SLOT(setValue(int)));
использует Qt::DirectConnection, т.е. setValue(int) в результате вызывается из порождённого потока.
Используйте Qt::QueuedConnection.
Код:
connect(m_at, SIGNAL(valueChanged(int)), m_pbProgress, SLOT(setValue(int)), Qt::QueuedConnection);

Ну а чтобы понять что у Вас там не компилится нужен весь код с "распределением по файлам".

PS Если Qt 3.x.x то может пригодится void QApplication::postEvent ( QObject * receiver, QEvent * event ) [static]
Записан
ритт
Гость
« Ответ #5 : Июль 23, 2008, 07:05 »

ыы...алекс тоже обманулся
я не обратил внимания, но алекс совершенно прав -
Цитировать
Используйте Qt::QueuedConnection.
Записан
spirit
Гость
« Ответ #6 : Июль 23, 2008, 08:35 »

ладно, понял, буду в селед.раз каммент писать, что бы не вводить в заблуждение.  Улыбающийся
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #7 : Июль 23, 2008, 11:56 »

Alex03, Константин вы неправы насчет коннекта. По умолчанию стоит параметр Qt::AutoConnection. Открываем ассистант и смотрим что это значит:

Цитировать
If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly, as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection.


Укажите в коннекте явно Qt::DirectConnection и вы получите assert вида:

Цитировать
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread a19768. Receiver '' (of type 'MainWindow') was created in thread 3d7a40", file kernel qcoreapplication.cpp, line 279


Так что курим ассистант внимательнее.
« Последнее редактирование: Июль 23, 2008, 12:04 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
neosapient
Гость
« Ответ #8 : Июль 23, 2008, 12:11 »

Спасибо.
Вроде заработало.
Сегодня заново пересобрал проект и ошибка ушла.

Примерчик тоже показательный - spirit, отдельное спасибо
Записан
Alex03
Гость
« Ответ #9 : Июль 23, 2008, 12:53 »

Alex03, Константин вы неправы насчет коннекта....
Действительно гдето я глюканул, считая что Qt::AutoConnection меняется на Qt::DirectConnection или Qt::QueuedConnection в момент вызова connect(), а не в момент "испускания" сигнала.
Посыпаю голову пеплом и приношу извинениея тем кого ввёл в заблуждение.

Цитировать
If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly, as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection.
Судя по исходникам для Qt::DirectConnection не только receiving object, но и sender должны жить в emit-потоке.
Код:
        if ((c->type == Qt::AutoConnection
             && (currentThreadData != sender->d_func()->threadData
                 || c->receiver->d_func()->threadData != sender->d_func()->threadData))
            || (c->type == Qt::QueuedConnection)) {

Цитировать
Так что курим ассистант внимательнее.
Угу!
Записан
ритт
Гость
« Ответ #10 : Июль 23, 2008, 23:07 »

2Пастор
ну, не так уж и неправы. такие вещи желательно связывать ивентами вместо блокирующих вызовов - хоть в разных потоках, хоть в одном. поэтому я обычно в подобных местах явно указываю Qt::QueuedConnection...вот и спириту так же советую.
а про курение доков - это прямо обидно как-то...
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #11 : Июль 23, 2008, 23:48 »

2Пастор
ну, не так уж и неправы. такие вещи желательно связывать ивентами вместо блокирующих вызовов - хоть в разных потоках, хоть в одном. поэтому я обычно в подобных местах явно указываю Qt::QueuedConnection...вот и спириту так же советую.
а про курение доков - это прямо обидно как-то...

В основном ответ адресовался Alex03. Но ты полностью подписался под постом Alex03, поэтому в свой ответ добавил и обращение к тебе. Так что необижайсо, не со зла же Подмигивающий
« Последнее редактирование: Июль 23, 2008, 23:53 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
fightcat
Гость
« Ответ #12 : Июль 31, 2008, 17:19 »

На тему исходной ошибки - Error: Signals cannot have access specifier - сигнал не может иметь спецификатор доступа. Т.е. у Вас, видимо, было написано public signals: или private signals:. В то время как может быть только signals: и все - тролли считают, что приватные сигналы не имеют смысла.
Записан
ритт
Гость
« Ответ #13 : Июль 31, 2008, 21:03 »

signals == protected
public protected == бред
вот и ошибка
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.076 секунд. Запросов: 23.