Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: alexlogvinenkoit от Ноябрь 15, 2011, 11:53



Название: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 11:53
Здравствуйте!

Такая вот проблема: есть класс, наследующийся от QStackedWidget, в нем много классов, наследующихся от QWidget...
Есть поток, который запускается из QStackedWidget (pthread).

Так вот, в этом потоке мне нужно менять текущий индекс QStackedWidget (QStackedWidget::setCurrentIndex(int index));
Прога на этом моменте вылетает, вот, что пишет:

Цитировать
<unknown>: Fatal IO error 11 (Ресурс временно недоступен) on X server :0.0.

Код:
class WidgetStacked : public QStackedWidget
{
    //...
    explicit WidgetStacked (QWidget * parent) : QStackedWidget(parent)
    {
        //...
        pthread_t th;
        pthread_create(&th, 0, ThreadCallback, (void *)this);
    }
    friend void * ThreadCallback(void * param);
};

void * ThreadCallback(void * param)
{
    //...
    ((WidgetStacked *)param)->setCurrentIndex(0);
}

При чем, если просто поменять текст лейбы или еще какие-то действия с дочерними виджетами - то работает...
Подскажите, пожалуйста, в чем может быть дело и как можно решить данную проблему.

Спасибо!


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 12:41
Есть идея, только не знаю как реализовать (и вообще возможно ли)...

Если программировать на C# - такая проблема всплывает очень часто.
Ее решают очень просто - создают делегат.

Есть ли в Qt (или даже лучше в C++) делегаты или хотя бы что-то отдоленно похожее?
Просто никогда не сталкивался с токого рода проблемой с C++


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 12:58
Почитай про QThread и систему сигнал-слот (есть специальный режим для передачи сигналов между потоками).
Изменять GUI можно только из главного потока!


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 13:07
Повторюсь: из отдельного потока можно делать определенные действия с GUI (я менял текст лейбы (удачно)).
Вылетает только при вызове функции setCurrentIndex(int index).

P.S. Пробовал сделать public-функцию SetIndex(int index), в ней уже вызвать setCurrentIndex(index), а ьиз потока вызывать SetIndex(int index). Тоже не помогает.
Пробовал еще послать сигнал (emit) - тоже ничего :)

Да и еще, поток не QThread, а pthread_t...


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 13:24
Повторюсь: из отдельного потока можно делать определенные действия с GUI (я менял текст лейбы (удачно)).
Вылетает только при вызове функции setCurrentIndex(int index).
Можешь повторяться сколько угодно, но
Изменять GUI можно только из главного потока!
Вся перерисовка в Qt делается асинхронно, поэтому при изменении текста ничего не упало.
Изменение stacking-order и не только его на X11 делается синхронно (со стороны Qt, вернее Xlib) поэтому и падает.

Цитировать
P.S. Пробовал сделать public-функцию SetIndex(int index), в ней уже вызвать setCurrentIndex(index), а ьиз потока вызывать SetIndex(int index). Тоже не помогает.
От перестановки слогаемых сумма не меняется...

Цитировать
Пробовал еще послать сигнал (emit) - тоже ничего
Кому и как слал?

Цитировать
Да и еще, поток не QThread, а pthread_t...
Тем более...


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 13:29
Спасибо, проблему понял.
Вот только решения не понял... Решение какое-нибудь найти можно?


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 13:34
Спасибо, проблему понял.
Вот только решения не понял... Решение какое-нибудь найти можно?
Всё зависит от того как быстро ты сможешь перейти от pthreads к QThread.


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 13:44
Дело в том, что изначально-то и был QThread, но это поток читает из COM-порта, а при использовании QThread - на моменте чтения прога вылетает. Уже даже не помню что писал, но точно какая-то ошибка была.

А если из потока pthread вызвать поток QThread? И в потоке QThread просто вызвать функцию setCurrentIndex(int index)?

Т.е. так же, как в дочерних виджетах вызываю ((QStackedWidget *)->parent())->setCurrentIndex(int index)?


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 13:55
Для переключения нужно будет посылать сигнал через очередь сообщений, это можно сделать еще и с помощью invokeMethod.


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: thechicho от Ноябрь 15, 2011, 14:58
//Вся перерисовка в Qt делается асинхронно, поэтому при изменении текста ничего не упало.
Изменение stacking-order и не только его на X11 делается синхронно (со стороны Qt, вернее Xlib) поэтому и падает.

а я то думал, почему у меня прога в убунту падает.
итс факин щит.
придется все переделывать. таскать указатель на гуишный элемент, сначала в поток, потом обратно в гуи, через сигналы и слоты. ну чо бл за маразм :-\


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 15:03
таскать указатель на гуишный элемент, сначала в поток, потом обратно в гуи, через сигналы и слоты. ну чо бл за маразм :-\
Действительно маразм. А зачем так делать  ???


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 15:22
Маразм, согласен!

Я бы посмотрел в сторону Java, но проект уже написан, остается пару вещей сделать.
И вот эта проблема - одна них.

Если кто знает, каким образом можно ренить проблему, отпишитесь, please, очень надо!


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 16:30
Если кто знает, каким образом можно ренить проблему, отпишитесь, please, очень надо!
Дык решение очевидно - не "таскать указатель на гуишный элемент, сначала в поток, потом обратно в гуи".


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: thechicho от Ноябрь 15, 2011, 16:34
допустим запускается 100 потоков. как тогда сделать синхронизацию каждого потока с гуи? (QLineEdit, QLabel)


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 16:35
Цитировать
Дык решение очевидно - не "таскать указатель на гуишный элемент, сначала в поток, потом обратно в гуи".

Немного не понял... Покажите на примере, please...


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 16:42
Немного не понял... Покажите на примере, please...
Нельзя дергать слот виджета из другого потока напрямую:
Код
C++ (Qt)
stackWidget->setCurrentIndex( 100500 );    // ТАК НЕЛЬЗЯ
 

но можно его дернуть через очередь сообщений, в этом случае он выполниться в контексте главной (GUI) нитки.
Код
C++ (Qt)
QMetaObject::invokeMethod( stackWidget, "setCurrentIndex", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG( int, 100500 ) );
 


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 16:46
допустим запускается 100 потоков. как тогда сделать синхронизацию каждого потока с гуи? (QLineEdit, QLabel)
  • Завести в производном от QThread классе сигнал, допустим, resultIsReady( const QString& ).
  • Связать этот сигнал с QLineEdit::setText( const QString& ).
  • После получения результата в потоке испускать этот сигнал resultIsReady( text_to_show ).


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 16:57
Цитировать
но можно его дернуть через очередь сообщений, в этом случае он выполниться в контексте главной (GUI) нитки.

Я попробовал, но метод возвращает false...
Вопрос на засыпку: метод нужно вызывать только из QThread или из pthread тоже можно?

P.S. Спасибо за код!


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 17:03
Я попробовал, но метод возвращает false...
В консоль что нибудь пишет?


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: thechicho от Ноябрь 15, 2011, 17:05
// Связать этот сигнал с QLineEdit::setText( const QString& ).
пример кода, плиз?
для каждого потока свой QLineEdit
я не догоняю как такую связь (без слота) осуществить :-\


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 17:05
В консоль пишет только то, что я сам говорю писать... Т.е. если вернет true я пишу в консоль тру, если false - то false...
В остальном - никаких ошибок, warnings и т.д. Даже прога не вылетает :)


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 17:07
// Связать этот сигнал с QLineEdit::setText( const QString& ).
пример кода, плиз?
для каждого потока свой QLineEdit
я не догоняю как такую связь (без слота) осуществить :-\
Дык QLineEdit::setText() и есть слот  ???


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 17:11
Попробуй так:
Код
C++ (Qt)
QMetaObject::invokeMethod( stackWidget, "setCurrentIndex", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG( int, 100500 ) );
 


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 17:16
Попробуй так:
Код
C++ (Qt)
QMetaObject::invokeMethod( stackWidget, "setCurrentIndex", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG( int, 100500 ) );
 
Скорее всего тоже не прокатит. QGenericReturnArgument() не нужен:
Код
C++ (Qt)
QMetaObject::invokeMethod( stackWidget, "setCurrentIndex", Qt::QueuedConnection, Q_ARG( int, 0 ) );


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: thechicho от Ноябрь 15, 2011, 17:19
// Дык QLineEdit::setText() и есть слот
пример кода, плиз.
QLineEdit для каждого потока свой. 10 потоков.


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: BRE от Ноябрь 15, 2011, 17:26
Скорее всего тоже не прокатит.
Должен прокатить. :)


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: alexlogvinenkoit от Ноябрь 15, 2011, 17:28
Заработало!!!

Всем огромное спасибо!!! Прямо выручили!

Код:
QMetaObject::invokeMethod( stackWidget, "setCurrentIndex", Qt::QueuedConnection, Q_ARG( int, 0 ) );


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: GreatSnake от Ноябрь 15, 2011, 17:33
// Дык QLineEdit::setText() и есть слот
пример кода, плиз.
QLineEdit для каждого потока свой. 10 потоков.

Как-то так:
Код
C++ (Qt)
class Thread : public QThread
{
Q_OBJECT
   ...
Q_SIGNALS:
   void resultIsReady( const QString& );
 
protected:
   void run()
   {
        ...
        emit resultIsReady( "here must be resulted text" );
        ...
   }
};
 
// usage
{
   ...
   QLineEdit* le = new QLineEdit();
   Thread* thr = new Thread();
   connect( thr, SIGNAL( resultIsReady( QString ) ), le, SLOT( setText( QString ) ) );
   ...
}
 


Название: Re: Изменение текущего индекса QStackedWidget из потока pthread
Отправлено: thechicho от Ноябрь 15, 2011, 18:08
а все допер) я ставил this, SLOT() поэтому понять не мог, почему не прокатывает  :D
биг сенкс :)