Qt:QGraphicsScene не обновляется, когда я ожидал бы, что это

StackOverflow https://stackoverflow.com/questions/715920

  •  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().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top