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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: GUI и 2 потока  (Прочитано 6023 раз)
alex12
Гость
« : Январь 31, 2007, 12:59 »

Всем привет!

[Qt 4.2.2 MinGW]

Есть программа с 2 потоками. Как написано в документации -- все обращения к GUI только из основного потока.

Но мне очень надо из дополнительного потока вызвать тривиальное окошко QInputDialog::getInteger().

Когда я его вызов нахально ставлю из дополнительного потока -- то все в основном работает, но иногда (примерно 20%) программа падает.

Может можно как-то приостановить/заблокировать основной поток и вызвать окошко ввода откуда мне удобно, а не городить дикие конструкции с флажками, таймерами или сигналами/слотами?
Записан
Dendy
Гость
« Ответ #1 : Январь 31, 2007, 13:57 »

Сказано нельзя - значит нельзя. И неважно в каком процентном соотношении валится прога, хоть в 0.01% случаев.

Делать примерно так:

Код:
void MyThread::run()
{
  ...
  // need to stop thread and show dialog
  QWaitCondition condition;
  QMutex mutex;
  qApp->postEvent( object_from_main_thread, MyEvent( &condition ) );
  {
    QMutexLocker locker( &mutex );
    condition.wait( &mutex );
  }
  // now dialog closed
}

bool ObjectFromMainThread::event( QEvent * e )
{
  if ( e->type() == MY_EVENT )
  {
    MyEvent * me = static_cast<MyEvent*>( e );
    show_my_dialog();
    me->condition->wakeAll();
    return true;
  }
  // ...
}
Записан
alex12
Гость
« Ответ #2 : Январь 31, 2007, 14:08 »

Просто в Qt 3 я что-то слышал о блокировке главного потока. Еще интересно, как по правильному сделать передачу обратно данных из диалога?
Записан
Tonal
Гость
« Ответ #3 : Январь 31, 2007, 14:11 »

Это надо в фак. Однозначно! ;-)
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #4 : Февраль 01, 2007, 00:45 »

+1

а из диалога - точно так же. Эвентом. Хотя 4.х вроде поддерживает межпотоковые сигналы...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Dendy
Гость
« Ответ #5 : Февраль 01, 2007, 02:04 »

Передавать сигналами будет правильней. Только вот пример тогда будет немного поболее. Ибо испускать сигнал нужно не из потока (QThread), а из обьекта, что принадлежит етому потоку, собьІтия которого обрабатьІваются в теле QThread::run(). Или принудительно вьІставлять QueuedConnection.
Записан
Tonal
Гость
« Ответ #6 : Февраль 01, 2007, 08:22 »

Цитата: "alex12"
Еще интересно, как по правильному сделать передачу обратно данных из диалога?

Вроде достаточно чуть подправить код Dendy:
Цитата: "Dendy"
Код:
void MyThread::run()
{
  ...
  // need to stop thread and show dialog
  QWaitCondition condition;
  QMutex mutex;
  MyEvent ev( &condition )
  qApp->postEvent( object_from_main_thread, ev);
  {
    QMutexLocker locker( &mutex );
    condition.wait( &mutex );
  }
  //Получаем код возврата:
  ... = ev->dialogResult();
}

bool ObjectFromMainThread::event( QEvent * e )
{
  if ( e->type() == MY_EVENT )
  {
    MyEvent * me = static_cast<MyEvent*>( e );
    int dlg_res = show_my_dialog();
    //Запоминаем код в MyEvent
    me->setDialogResult(dlg_res);
    me->condition->wakeAll();
    return true;
  }
  // ...
}

Или я чего-то не учёл?
Записан
Sergeich
Гость
« Ответ #7 : Февраль 01, 2007, 14:03 »

Цитата: "Tonal"
Или я чего-то не учёл?
Не учел Улыбающийся Читаем в ассистанте:
QApplication::postEvent
... The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted. ...
Во-первых, нельзя заводить экземляр MyEvent в стеке, т.к. он будет удален через deletе, и если после этого прога просто грохнется тебе сильно повезет Улыбающийся , т.к. если она выживет, то будет вытворять всякие гадости в различных местах памяти Улыбающийся
Во-вторых, удуалением экземляра MyEvent управляет кутевая событийная очередь, и скорей всего он будет удален сразу после выхода из ObjectFromMainThread::event( QEvent * e ), так что не факт, что при обращении к нему в MyThread::run() он будет еще жив.
Записан
Dendy
Гость
« Ответ #8 : Февраль 01, 2007, 15:46 »

В стеке создавать MyEvent для postEvent() нельзя! Навернёте всю программу. Указатель на MyEvent должен теряться сразу же после вьІзова postEvent(). Ибо его удаляет из кучи сам QCoreApplication.

Как передать данньІе диалога обратно в поток? Очень просто. В MyEvent сохраняете указатель на некую структуру с данньІми. Так как поток замрёт до отработки диалога - заботиться о потере етих данньІх по указателю и одновременному их используется не нужно.

Код:
struct ReturnData
{
  int code;
  QString message;
};

ReturnData data;
qApp->postEvent( object_from_main_thread, new MyEvent( &data, &condition ) );
...
if ( data.code == 123 )
  qDebug() << "Dialog returned message: " << data.message;
Записан
Tonal
Гость
« Ответ #9 : Февраль 01, 2007, 19:17 »

Цитата: "Dendy"
В стеке создавать MyEvent для postEvent() нельзя! Навернёте всю программу.

Писал основываясь исключительно на вашем коде.
Код:
qApp->postEvent( object_from_main_thread, MyEvent( &condition ) );

Не сверился с ассистентом - вот и нарвался. ;-)
Цитата: "Dendy"
Как передать данньІе диалога обратно в поток? Очень просто. В MyEvent сохраняете указатель на некую структуру с данньІми. Так как поток замрёт до отработки диалога - заботиться о потере етих данньІх по указателю и одновременному их используется не нужно.

Это примерно и имелось в виду.
С сигналами стоит заморачиваться только если нужна более сложная коммуникация с GUI-я и потока.[/code]
Записан
alex12
Гость
« Ответ #10 : Февраль 02, 2007, 11:37 »

Всем спасибо. Все же сколько может быть мороки от тривиального QInputDialog::getInteger()!  Веселый
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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