В QGraphicsScene отсутствует обновление определенного элемента

У меня есть приложение, в котором вы можете смотреть повторы для данной 2D-игры:

По сути, транспортное средство движется по карте. Изображение сосредоточено на транспортном средстве, поэтому карта прокручивается во время повтора, что-то вроде Micro Machines (просто для понимания, настоящая игра не Micro Machines). ).


(источник: randomracket .com)

В моей сцене карта статична, пока машина движется. Вид прокручивается для каждого кадра повтора, так что транспортное средство находится в центре. По соображениям производительности карта разбита на несколько QGraphicsPixmapItems.

Режим обновления области просмотра установлен на QGraphicsView::BoundingRectViewportUpdate. Метод индексирования элементов установлен на QGraphicsScene::NoIndex.

В большинстве случаев все работает нормально. Но когда карта больше обычного, транспортное средство не обновляется. Вид прокручивается, а плитки хорошо обновляются; но не транспортное средство, если я не запускаю полное обновление окна просмотра, увеличивая/уменьшая масштаб (поэтому я знаю, что элемент правильно расположен).

boundingRect транспортного средства устанавливается раз и навсегда и является допустимым (см. ниже, дано в логических координатах). Я не рисую внешний прямоугольник, ограничивающий элемент.

некоторый пример вывода отладки (только третья конфигурация не работает):

ok :
vehicle->boundingRect() : QRectF(-1.9391,-1.9391 3.8782x3.8782)
scene->sceneRect() : QRectF(-117.543,-38.3826 138.834x40.3217)
SCENE_CACHING : 85 tiles

ok :
vehicle->boundingRect() : QRectF(-2.88489,-2.88489 5.76979x5.76979)
scene->sceneRect() : QRectF(-68.8843,-18.2202 187.989x119.277)
SCENE_CACHING : 308 tiles

nok : vehicle won't update
vehicle->boundingRect() : QRectF(-3.45546,-3.45546 6.91092x6.91092)
scene->sceneRect() : QRectF(-64.2988,-107.802 188.927x187.445)
SCENE_CACHING : 506 tiles

Я попытался отладить проход обновления, и событие рисования действительно исключает регион, в котором находится транспортное средство...

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

Изменить:

Qt: 4.8.1, и я видел проблему и с предыдущими версиями.

ОС: Windows XP SP3, на других ОС пока не проверял

У меня не получилось воспроизвести проблему на минимальном примере. Минимальный пример просто работает так, как ожидается. В реальной жизни делается вот что:

  1. Карта читается из файла. Он состоит из сотен полигонов, ограничивающих землю/небо (каждый из которых графически состоит из слоев полигонов, ребер и вершин), тысяч изображений и текстур, которые затем обрезаются по земле или небу, и некоторых других элементов.

  2. Я вычисляю все вырезки, а затем визуализирую сцену в QImage. Изображение разбито на несколько QGraphicsPixmapItem, добавленных в сцену, в то время как прежние элементы удаляются из сцены и удаляются (кстати, ошибка также возникла, когда я не удалил и не удалил прежние элементы).

  3. Повтор запущен

Я думаю, что внутренности Qt Graphics испорчены, но я не могу понять, как его очистить/сбросить.

Вот пример графики (чтобы проиллюстрировать, что я имею в виду под землей/небом). Карта может быть довольно большой.


(источник: kopasite.net)


person azf    schedule 14.06.2012    source источник
comment
Как вы прокручиваете вид? Вы используете QGraphicsView::centerOn?   -  person Stephen Chu    schedule 14.06.2012
comment
Нет, я использую полосы прокрутки QGraphicsView, чтобы сосредоточиться на чем-то, вот так   -  person azf    schedule 14.06.2012
comment
Я знаю, что это много, но вы могли бы опубликовать рабочий минимальный пример, который дублирует проблему? Кроме того, какая ОС и версия Qt?   -  person Dave Mateer    schedule 17.06.2012
comment
Вы пробовали QGraphicsItem::update() для автомобиля в дополнение к QGraphicsScene::update()? Кажется, что по какой-то причине представление не думает, что ему нужно перекрашивать элемент, возможно, потому, что его положение рисования не меняется.   -  person Anthony    schedule 18.06.2012
comment
это не помогает к сожалению. @DaveMateer Я пытаюсь сделать минимальный пример, но не знаю, воспроизведет ли он проблему.   -  person azf    schedule 18.06.2012
comment
Как вы двигаете транспортное средство? Через setPos()?   -  person Anthony    schedule 18.06.2012
comment
@Энтони, да, я использую setPos() для перемещения предмета транспортного средства по сцене.   -  person azf    schedule 19.06.2012
comment
Означает ли, что транспортное средство не обновляется, что сцена или представление не вызывает соответствующий метод (точка останова не срабатывает) или только то, что вы не видите транспортное средство. Может ли быть так, что транспортное средство нарисовано за картой?   -  person Johannes S.    schedule 19.06.2012
comment
Вы пытались использовать QGraphicsScene::invalidate(...), чтобы сделать недействительными части сцены, которые должны быть перерисованы? Это работает, когда вы используете FullViewportUpdate ? Если да, это слишком медленно для вас?   -  person Johannes S.    schedule 19.06.2012
comment
@ЙоханнесС. Я имел в виду, что точка останова не сработала. FullViewportUpdate было бы слишком тяжело. НО ! звонок QGraphicsScene::invalidate(xxx, ItemLayer) сделал свое дело. Кажется, я неправильно понял документацию Qt по этому методу. Опубликуйте ответ, чтобы я мог принять его.   -  person azf    schedule 19.06.2012


Ответы (2)


Взяв мой комментарий сверху в качестве ответа:

Вам нужно использовать QGraphicsScene::invalidate(...), чтобы сделать недействительными части сцены, которые должны быть перерисованы.

person Johannes S.    schedule 20.06.2012
comment
Спасибо за идею. Иногда чтения документации недостаточно. Чтобы быть более точным, я использовал QGraphicsScene::invalidate(bRect,ItemLayer), где bRect — ограничивающий прямоугольник моего элемента в координатах сцены. И ItemLayer, потому что я не использую ни фон, ни передний план. - person azf; 20.06.2012

Я считаю, что это похоже на проблему, с которой я столкнулся при работе с большим количеством объектов QGraphicsItem. В конце концов я решил свою проблему, оптимизировав количество QGraphicsItems, которые у меня были на экране в любой момент времени, и не кэшируя QGraphicsItems, которые не нужно было кэшировать.

Простой способ проверить, является ли это вашей проблемой:

vehicle->setCacheMode(QGraphicsItem::NoCache);

Что должно вызывать метод рисования на вашем автомобиле каждый раз, когда его нужно нарисовать.

person effjae    schedule 18.06.2012
comment
Я попробовал то, что вы предложили (даже если в документе Qt указано, что режим по умолчанию — NoCache), но безуспешно. Однако вы правы, что это происходит только тогда, когда задействовано много предметов. Но это только для того, чтобы сделать фон один раз, затем я удаляю все бесполезные элементы. - person azf; 18.06.2012