Qt:QGraphicsScene не обновляется, когда я ожидал бы, что это
-
23-08-2019 - |
Вопрос
Хорошо, итак, у меня есть QGraphicsScene
в классе под названием eye.Я вызываю функцию:
void eye::playSequence(int sequenceNum) {
for (int i=0; i<sequences[sequenceNum].numberOfSlides(); i++) {
presentSlide(sequenceNum, i);
time_t start;
time(&start);
bool cont=false;
while (!cont) {
time_t now;
time(&now);
double dif;
dif=difftime(now, start);
if (dif>5.0)
cont=true;
}
}
}
который для каждого слайда вызывает:
void eye::presentSlide(int sequenceNum, int slideNum) {
Slide * slide=sequences[sequenceNum].getSlide(slideNum);
QGraphicsPixmapItem * pic0=scene.addPixmap(slide->getStimulus(0)->getImage());
pic0->setPos(0,0);
QGraphicsPixmapItem * pic1=scene.addPixmap(slide->getStimulus(1)->getImage());
pic1->setPos(horizontalResolution-350,0);
QGraphicsPixmapItem * pic2=scene.addPixmap(slide->getStimulus(2)->getImage());
pic2->setPos(horizontalResolution-350,verticalResolution-450);
QGraphicsPixmapItem * pic3=scene.addPixmap(slide->getStimulus(3)->getImage());
pic3->setPos(0,verticalResolution-450);
}
Теперь я бы ожидал, что это отобразит один набор изображений, подождет 5 секунд, затем отобразит следующий и так далее.Вместо этого он ничего не отображает до тех пор, пока не будут обработаны все слайды, а затем не будут показаны последние четыре изображения.Я пытался дозвониться scene.update()
в каждом месте, которое я мог представить, и это ничего не дало.Похоже, что сцена обновляется только тогда, когда playSequence
возвращает функция.Есть какие-нибудь идеи, что здесь может происходить?
Решение
Это тот тип поведения, который часто наблюдается в графических интерфейсах, управляемых событиями, когда кто-то хочет выполнить непрерывную анимацию.Я собираюсь предположить, что eye::playSequence вызывается нажатием кнопки или, может быть, с какого-то момента во время запуска кода приложения?В любом случае, вот что происходит.
Qt использует основной поток приложения для управления циклом событий.Цикл событий выглядит примерно так:
while(app_running)
{
if(EventPending)
ProcessNextEvent();
}
Проблема, которую вы видите, заключается в том, что обновления экрана выполняются во время события рисования.Если вы запускаете какой-либо код во время события щелчка мыши или любого другого события, то весь выполняемый вами рисунок ставится в очередь и будет выведен на экран при следующем событии рисования.Иногда требуется некоторое время, чтобы до этого дошло.
Лучший способ решить эту проблему - немного изменить свой подход.Один из способов - отбросить цикл while и настроить QTimer на срабатывание каждые 5 секунд.В слоте таймера вы можете нарисовать один слайд.Когда таймер сработает снова, нарисуйте следующий слайд и т.д.
Если вам нужно более прямое и менее элегантное быстрое решение, попробуйте вызвать qapp-> processEvents() сразу после вызова presentSlide(sequenceNum, i).Это (в большинстве случаев) заставит приложение удалить все события, поставленные в очередь, которые должны включать события рисования.
Я должен также упомянуть, что eye::presentSlide() просто добавляет новые объекты сцены к сцене на каждой итерации, покрывая те, которые были добавлены во время последнего вызова.Думайте о сцене как о дверце холодильника, и когда вы вызываете scene().addXXX, вы бросаете больше магнитов на холодильник на дверь :)
Другие советы
Вам необходимо разрешить запуск цикла событий приложения, чтобы постоянно обновлять пользовательский интерфейс.Самый простой способ сделать это из вашего кода - вызвать QApplication::processEvents() во внутреннем цикле while.
Многие люди сочли бы ваш цикл while неэффективным - в конце концов, вы просто ждете истечения определенного периода времени.Возможно, вы захотите подумать о реструктуризации своего кода, чтобы вместо него использовать таймер.
Вы могли бы создать объект QTimer в конструкторе вашего класса eye, установить тайм-аут в 5 секунд и подключить его сигнал timeout() к слоту в вашем классе eye, который обновляет индекс в наборе слайдов и вызывает presentSlide().Вы бы запустили таймер в функции playSequence().