LINUX.ORG.RU

[qt] QWidget::setEnabled() doesn't work as expected.

 


0

0

Кто-нибудь разбирался с этой тварью? Она, часом, не через сигналы реализована?

Задача проста как три копейки - заткнуть интерфейс на определенный срок до наступления события. Реализовано так:

void MainWindow::on_pushButton_clicked()
{
    this->setEnabled(false);
    thread.stopDoSomeUsefullThing();
    this->setEnabled(true);
}

stopDoSomeUsefulThing() отрабатывает на ура, но интерфейс даже ухом не ведет и после ожидания охотно обрабатывает все поставленные в очередь xEvent'ы.

ЧЯДНТ?

ЗЫ. Сама отработка setEnabled() в принципе происходит, если вешать по одному вызвову на слот.

★★★★★

Последнее исправление: LamerOk (всего исправлений: 1)

Сделал воркэраунд через жо^W сигналы.

LamerOk ★★★★★
() автор топика

>после ожидания охотно обрабатывает все поставленные в очередь xEvent'ы.

qApp->processEvents() перед setEnabled( true )

summatus
()

Я так понял ситуация у вас приблизительно следующая: по нажатию на кнопку, пока что-то выполняется в другом потоке, GUI умирает и натыканые по замороженому окну события потом скопом обрабатываются. Другими словами срабатывают нажатия на кнопки и прочее.

Если так, то у вас изначально неверная архитектура - GUI должен работать всегда с мгновенным откликом. QWidget::enabled не чистит автоматически события, а просто меняет флаг в машине состояний. Тем более, что события спонтанные - они не могут обработаться сразу, а ждут, пока цикл событий не войдёт в следующую итерацию.

В вашем случае достаточно сделать хак - перед оживлением интерфейса почистить или протолкнуть события:

void MainWindow::on_pushButton_clicked() 
{ 
    this->setEnabled(false); 
    thread.stopDoSomeUsefullThing();

    QCoreApplication::sendPostedEvents( this );
    или
    QCoreApplication::removePostedEvents( this );

    this->setEnabled(true); 
} 
Dendy ★★★★★
()
Ответ на: комментарий от summatus

Спасибо.

Я, грешным делом, предполагал, что это делается внутри setEnabled().

LamerOk ★★★★★
() автор топика
Ответ на: комментарий от Dendy

> по нажатию на кнопку, пока что-то выполняется в другом потоке, GUI умирает и натыканые по замороженому окну события потом скопом обрабатываются.

В первую очередь проблемой было то, что после выхода из setEnabled(false) гуйня по-прежнему была активна вплоть до полного возврата из обработчика слота.

QCoreApplication::removePostedEvents( this );


Ога. Тоже интересно.

LamerOk ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

Да, summatus более правильно подсказал - протолкнуть события для всех обьектов, так как Qt спонтанные события растасовывает по разным виджетам.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

QCoreApplication::sendPostedEvents( this );

Во-первых нет функции с таким набором аргументов, во-вторых зачем доставлять события, они и сами придут, т.е. это не поможет ему их отфильтровать.

QCoreApplication::removePostedEvents( this );

You should never need to call this function. If you do call it, be aware that killing events may cause receiver to break one or more invariants.

На практике это означает, что некоторые виджеты начнут себя вести иначе после её вызова.

summatus
()
Ответ на: комментарий от LamerOk

В первую очередь проблемой было то, что после выхода из setEnabled(false) гуйня по-прежнему была активна вплоть до полного возврата из обработчика слота.

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

Нужно так:

this->setEnabled(false);
this->repaint();
thread.stopDoSomeUsefullThing();
Dendy ★★★★★
()
Ответ на: комментарий от summatus

Во-первых нет функции с таким набором аргументов

Подразумевалось конечно же:

If event_type is 0, all the events are sent for receiver.

во-вторых зачем доставлять события, они и сами придут, т.е. это не поможет ему их отфильтровать.

Чтобы случайно не доставить события другим обьектам, которые могли бы повлиять на машину состояний в текущем стеке в то время как эти события должны прийти асинхронно. Например по какому-то событию это окно вообще будет удалено, а следующей строкой будет идти this->setEnabled(true), тогда как this указывает уже на мусор.

На практике это означает, что некоторые виджеты начнут себя вести иначе после её вызова.

Да, вы абсолютно правы.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

> Нужно так:

Ок, всем спасибо.

LamerOk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.