Почему пользовательский QGraphicsItem может вызвать перемещение сцены или представления, если boundingRect не пуст?

Мой класс C ++ Qt 4.8.1 для рисования перекрестия подклассов QGraphicsItem и реализует его paint () и boundingRect (). Метод paint () состоит из двух вызовов drawLine () и одного вызова drawText (). Источник находится в центре. boundingRect () также учитывает эти координаты (-, -, +, +), а также половину ширины пера в каждом направлении.

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

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

itemChange () вызывается много раз, но, похоже, не дает подсказки (на мой взгляд):

Crosshair::Crosshair being created, id= "1"  at  QPointF(63.6, 88.487) scenePos= QPointF(33.6, 58.487) 
Crosshair::Crosshair position QPointF(63.6, 88.487) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 1) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 1) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 33) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 33) 
Crosshair::itemChange  ItemFlagsChange QVariant(uint, 2081) 
Crosshair::itemChange  ItemFlagsHaveChanged QVariant(uint, 2081) 
[...]
Crosshair::itemChange  ItemPositionChange QVariant(QPointF, QPointF(63.6, 88.487) ) 
Crosshair::itemChange  ItemPositionHasChanged QVariant(QPointF, QPointF(63.6, 88.487) ) 
Crosshair::itemChange  ItemSceneChange QVariant(QGraphicsScene*, ) 
Crosshair::itemChange  ItemSceneHasChanged QVariant(QGraphicsScene*, ) 
[...]
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::itemChange  ItemVisibleChange QVariant(bool, true) 
Crosshair::itemChange  ItemVisibleHasChanged QVariant(bool, true) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
Crosshair::boundingRect  20 3 QRectF(-11.5,-11.5 21.5x21.5) 
...

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


Изменить Спасибо, Риатеш за совет. Некоторые дальнейшие результаты отладки показывают, что sceneRect () действительно изменен, он расширяет точно размер ограничивающего прямоугольника перекрестия, например с QRectF(0,0 1680x636) до QRectF(-11.5,-11.5 1691.5x647.5). ItemsBoundingRect сцены остается прежним. Я не упомянул ранее, что вид был масштабирован / преобразован с помощью fitInView(scene()->itemsBoundingRect(), Qt::KeepAspectRatio);, и заметил, что сдвига действительно не происходит, когда сцена просматривается на 100% (например, resetTransform()). Но я до сих пор не понимаю, как / почему меняется sceneRect (), когда я добавляю элемент в boundingRect (). Это должно быть связано с моей пользовательской реализацией, потому что добавление эллипса не вызывает сдвига сцены / вида.

Хорошо, начнем: я также не упомянул, что использую setFlag(QGraphicsItem::ItemIgnoresTransformations);, чтобы прицел оставался одинакового размера независимо от масштаба. Это, по-видимому, приводит к тому, что boundingrect "остается" в исходной точке сцены при добавлении, и игнорирует setPos ().

Продолжение следует ...


person handle    schedule 09.07.2013    source источник


Ответы (2)


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

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

Если вы хотите избежать такого поведения, вы можете использовать QGraphicsView::setSceneRect или QGraphicsScene::setSceneRect, чтобы исправить положение прямоугольника. Обратите внимание, что все, что находится за пределами установленного прямоугольника, будет недоступно и невидимо в представлении.

Также рассмотрите возможность перехода на QGraphicsPathItemQGraphicsScene::addPath). Его можно использовать для рисования перекрестия.

person Pavel Strakhov    schedule 09.07.2013

Я пытался решить проблему с помощью

QRectF save = scene->sceneRect();
scene->addItem( myGraphicsItem );
scene->setSceneRect( save );

как предлагает Риатеш на другой ноте, и это работает.

Однако я, к сожалению, до сих пор не до конца понимаю причину этого.

Вот что в документации говорится об этом флаге. :

QGraphicsItem :: ItemIgnoresTransformations

0x20

Элемент игнорирует унаследованные преобразования (т. Е. Его позиция по-прежнему привязана к его родительскому элементу, но родительский элемент или преобразование поворота, масштабирования или сдвига игнорируются). Этот флаг полезен для того, чтобы элементы текстовых меток оставались горизонтальными и немасштабируемыми, поэтому они все равно будут доступны для чтения, если представление будет преобразовано. Если установлено, геометрия вида элемента и геометрия сцены будут поддерживаться отдельно. Вы должны вызвать deviceTransform () для сопоставления координат и обнаружения столкновений в представлении. По умолчанию этот флаг отключен. Этот флаг был представлен в Qt 4.3. Примечание. Установив этот флаг, вы по-прежнему можете масштабировать сам элемент, и это преобразование масштаба повлияет на его дочерние элементы.

Вот некоторая, возможно, связанная информация:

person handle    schedule 12.07.2013