Установите вращение QGraphicsItem, перетаскивая дочерний элемент - PullRequest
0 голосов
/ 10 июня 2019

У меня есть поле QGraphicsItem с дочерним эллипсом (a QGraphicsEllipseItem):

Rotating parent by dragging child node

Я хочу позволить пользователю перетаскиватьэллипс вокруг, чтобы установить вращение коробки.Коробку следует поворачивать так, чтобы она указывала на центр эллипса при каждом перетаскивании эллипса независимо от положения круга (т. Е. Его можно перемещать дальше от зеркала или ближе к нему; это не имеет значения).Для этого я установил событие itemChange эллипса, чтобы захватить тип ItemPositionChange, а затем подать сигнал с обновленной позицией, который перехватывается родителем и используется для установки поворота родителя:

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

        # Add rotation node.
        self.node = Node(self.width, self.height / 2, parent=self)
        self.node.setPos(30, 0)
        self.node.POSITION_CHANGE.connect(self.set_angle_from_node)

    def set_angle_from_node(self, node, position):
        self.setRotation(math.degrees(math.atan2(position.y(), position.x())))


class Node(QGraphicsEllipseItem, QObject):
    RADIUS = 4
    POSITION_CHANGE = Signal(QGraphicsEllipseItem, QPointF)

    def __init__(self, origin_x, origin_y, **kwargs):
        # Call parent constructors separately due to a segmentation fault (https://bugreports.qt.io/browse/PYSIDE-800)
        QGraphicsEllipseItem.__init__(self, origin_x - self.RADIUS, origin_y - self.RADIUS,
                                      self.RADIUS * 2, self.RADIUS * 2, **kwargs)
        QObject.__init__(self)

        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemSendsGeometryChanges)
        self.setFlag(self.ItemIsSelectable)

    def itemChange(self, change, value):
        if change == self.ItemPositionChange:
            self.POSITION_CHANGE.emit(self, value)

        return super().itemChange(change, value)

(Обратите внимание, что класс Node наследуется от QObject, чтобы использовать возможности Signal.)

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

Parent rotates further than child

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

Я мог бы исправить это, развязав системы координат, сделав эллипс совершенно отдельным объектом сцены, а не дочерним объектом левого объекта, но я хочу сохранить этоИерархия по другим причинам, таким как возможность изменения положения системы «box + ellipse» путем перетаскивания поля.

Чтобы попытаться это исправить, я выяснил, что возвращаемое значение из метода itemChange эллипсаиспользуется для обновления положения эллипса, поэтому я попытался передать реальные новые координаты эллипса родительскому элементу, но переопределил значение y на 0 для возвращаемого значения, поэтому оно всегда было справа от правой стороны поля, как впервая диаграмма:

def itemChange(self, change, value):
    if change == self.ItemPositionChange:
        self.POSITION_CHANGE.emit(self, value)
        # Override coordinate used to update this ellipse's position
        value.setY(0)

    return super().itemChange(change, value)

Однако это также не решило проблему;дополнительное вращение все еще там и кажется еще более хаотичным.Я не уверен, почему это не помогло, но я также не уверен, что нет лучшего способа сделать это, чего мне не хватает.У кого-нибудь есть хорошая идея, как заставить это работать?

...