Масштабирование позиций GraphicsItems в GraphicsScene без изменения других свойств

Я размещаю кучу узлов на QGraphicsScene. Узлы представляют собой базовые эллипсы (QGraphicsEllipseItems). Он работает достаточно хорошо.

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

Я ищу формулу, которая лучше уравновешивает размер эллипса, количество эллипсов на сцене и масштаб сцены.

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

Может ли кто-нибудь посоветовать, как лучше всего добиться сбалансированного расположения?


person user595985    schedule 03.02.2015    source источник
comment
Узлы крошечные, потому что вы сделали их крошечными, вы можете легко увеличить их (не забудьте вызвать setSceneRect, иначе Qt попытается сохранить сцену в центре). Чтобы эллипсы оставались подходящего размера при масштабировании, см. Мой ответ.   -  person Trilarion    schedule 04.02.2015


Ответы (1)


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

Между сценой и видом есть матрица преобразования (2x3 для масштабирования, поворота, сдвига и перемещения). Вы можете получить его с помощью QGraphicsView.transform().

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

Вы не хотите этого. Хорошо, так почему бы не изменять их размер (в соответствии с текущим коэффициентом масштабирования) каждый раз, когда изменяется масштаб. Ну, это, вероятно, не очень эффективно.

Лучшее решение — не изменять масштаб вида, а просто масштабировать позиции вручную, сохраняя фиксированный масштаб. Таким образом, никакие свойства элементов, кроме их положения, не должны изменяться.

Пример (с использованием PySide и Python 3, но легко настраивается на PyQt и Python 2):

from PySide import QtGui, QtCore
import random

class MyGraphicsView(QtGui.QGraphicsView):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def wheelEvent(self, event):
        if event.delta() > 0:
            scaling = 1.1
        else:
            scaling = 1 / 1.1

        # reposition all items in scene
        for item in self.scene().items():
            r = item.rect()
            item.setRect(QtCore.QRectF(r.x() * scaling, r.y() * scaling, r.width(), r.height()))

app = QtGui.QApplication([])

scene = QtGui.QGraphicsScene()
scene.setSceneRect(-200, -200, 400, 400)
for i in range(100):
    rect = QtCore.QRectF(random.uniform(-180, 180), random.uniform(-180, 180), 10, 10)
    scene.addEllipse(rect)

view = MyGraphicsView(scene)
view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
view.resize(400, 400)
view.show()

app.exec_()

С помощью колесика мыши вы можете масштабировать позиции, и тогда это выглядит так:

введите здесь описание изображения

Что касается баланса размера и количества эллипсов - ну это все на ваше усмотрение. Общего правила нет. Я рекомендую не делать эллипсы больше, чем расстояние между эллипсами, иначе они будут перекрываться. В общем, я работаю с координатами сцены, которые составляют 1:1 с размерами представления в пикселях (как я сделал в приведенном выше примере, ширина представления 400 пикселей, ширина прямоугольника сцены 400 единиц). Тогда я легко представляю, какой будет размер эллипса 10, то есть 10 пикселей. Если я хочу больше, я использую больше, а если хочу меньше, я использую меньше. Но для этого нет никаких правил, это зависит от того, что вы хотите.

person Trilarion    schedule 03.02.2015