Модальный QProgressDialog::setValue() вызывает сбой вложенным циклом событий
Я только что написал некоторый код на основе QThread, который выполняет большие вычисления. Чтобы визуализировать прогресс, мне нужно открыть QProgressDialog. Диалог является модальным приложения (с использованием open ()), так как я не хочу разрешать изменения главного окна во время расчета. Поток испускает различные сигналы, которые позволяют конечному автомату связываться между GUI и потоком.
Два из сигналов, излучаемых рабочим объектом потока, - это "Progress" и "Finished". Если выдается "Progress", я обновляю QProgressDialog, используя setValue(). Если выбрано "Готово", диалог уничтожается.
В конце расчета происходит следующее:
- Событие "Прогресс" (100%) выброшено
- "Готово" испускается сразу после
- setValue(100) вызывается из-за события "Progress"
- Поскольку диалог модальный, setValue() вызывает processEvents()
- processEvents() доставляет событие "Завершено"
- Событие "Завершено" приводит к разрушению диалога в середине setValue (), что вызывает сбой
QProgressDialog ломает мою архитектуру, вызывая processEvents() в setValue(). Также мои соглашения о кодировании запрещают использование любых вложенных циклов событий (как в exec() и т. Д.).
У меня есть два вопроса:
Почему модальный диалог требует вложенного цикла событий? Из моего непонимания блокирование ввода родительских окон, кажется, не требует этого.
Можно ли использовать QProgressDialog модальным способом, но без вложенного цикла событий?
1 ответ
Ты должен использовать deleteLater()
уничтожить твой QProgressDialog
, Событие, которое удаляет ваш QProgressDialog
Объект обрабатывается в функции, которая принадлежит QProgressDialog
Сам объект, это сводится к законности вызова delete this;
внутри функции-члена C++ вы можете обратиться к этому вопросу из FAQ по isocpp C++ для получения дополнительной информации об этом. Суть в том, что вы должны гарантировать, что вы больше не получите доступ к любому члену объекта после совершения самоубийства...
так как вы не можете гарантировать это в Qt's QProgressDialog::setValue()
реализация, событие, которое delete
с QProgressBar
как это будет счастливо вызывать UB при следующем доступе к любому члену объекта (когда поднят в функции-члене). deleteLater
был специально разработан для решения этой проблемы, поскольку события отложенного удаления обрабатываются особым образом (они не обрабатываются QCoreApplication::processEvents()
). Это означает, что QProgressDialog
объект будет уничтожен после setValue
возвращает управление в цикл событий, а не в середине выполнения setValue
...
Всегда используйте deleteLater
в таких ситуациях При использовании равнины delete
внутри события вы должны убедиться, что это событие не обрабатывается при выполнении функции-члена этого объекта, и что оно не выполняется в результате испускания сигнала от этого объекта (с прямым сигналом / слот соединения), поскольку, в конце концов, сигнал - это просто функция-член, реализация которой обеспечивается MOC Qt)...