Qt: QGraphicsScene не обновляется, когда я ожидаю - PullRequest
3 голосов
/ 04 апреля 2009

Хорошо, поэтому у меня есть 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. Есть идеи, что здесь может происходить?

Ответы [ 2 ]

7 голосов
/ 04 апреля 2009

Вам необходимо запустить цикл событий приложения, чтобы обновлять пользовательский интерфейс. Самый простой способ сделать это из вашего кода - вызвать QApplication :: processEvents () во внутреннем цикле while.

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

Вы можете создать объект QTimer в конструкторе вашего класса глаз, установить время ожидания 5 секунд и подключить его сигнал timeout () к слоту в вашем классе глаз, который обновляет индекс в виде набора слайдов и вызывает presentSlide. (). Вы запускаете таймер в функции playSequence ().

7 голосов
/ 04 апреля 2009

Это тот тип поведения, который часто наблюдается в управляемых событиями структурах GUI, когда кто-то хочет делать непрерывную анимацию. Я собираюсь догадаться, что eye :: playSequence вызывается нажатием кнопки или, может быть, с какого-то момента во время запуска кода приложения? В любом случае, вот что происходит.

Qt использует основной поток приложения для запуска цикла событий. Цикл событий выглядит примерно так:

while(app_running)
{
  if(EventPending)
    ProcessNextEvent();
}

Проблема, которую вы видите, состоит в том, что обновления экрана выполняются во время события рисования. Если вы выполняете какой-либо код во время события щелчка мыши или любого другого события, то весь чертеж, который вы делаете, ставится в очередь и будет отображаться на экране при следующем событии рисования. Иногда требуется некоторое время, чтобы это погрузилось.

Лучший способ решить эту проблему - немного изменить свой подход. Один из способов - выбросить цикл while и настроить запуск QTimer каждые 5 секунд. В слоте таймера вы можете нарисовать один слайд. Когда таймер снова сработает, нарисуйте следующий слайд и т. Д.

Если вы хотите более прямое и менее элегантное быстрое исправление, попробуйте вызвать qapp-> processEvents () сразу после вашего вызова presentSlide (sequenceNum, i). Это (в большинстве случаев) заставит приложение удалять любые события в очереди, которые должны включать события рисования.

Я должен также упомянуть, что eye :: presentSlide () просто добавляет новые объекты сцены в сцену на каждой итерации, покрывая те, которые были добавлены во время последнего вызова. Думайте о сцене как о двери холодильника, и когда вы вызываете scene (). AddXXX, вы бросаете в дверь больше магнитов на холодильник:)

...