4

我正在用 PyQt 编写一个应用程序,它允许用户选择放置在 a 上的图像QGraphicsScene(使用 custom QGraphicsPixmapItem)。选择后,我希望图像上出现一个旋转手柄,用户可以用鼠标“抓取”并旋转,从而旋转QGraphicsPixmapItem. 基本上,我正在寻找您在选择形状时在 PowerPoint 中获得的旋转手柄功能。这似乎是许多人会实现的一个非常基本的功能,但我在网上找不到任何好的例子。谁能指出我正确的方向?

4

1 回答 1

4

让我们先把问题分成更小的问题,然后再把所有的东西组装起来。我在这个解决方案中使用 PyQt5。

1. 旋转一个 QGraphicsItem

为此,您需要setRotation在项目上使用以度数为单位的旋转角度。旋转将围绕 指定的点setTransformOriginPoint。通常一个人会采取一个形状的中心。如果您不指定此点,通常会采用形状的左上角。

2.拖一个QGraphicsItem

出于性能原因,QGraphicsItems 不可移动,也不会将位置更改发送到事件框架。通过设置适当的标志QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges,您可以改变它。另外QGraphicsItem不继承自QObject,因此对于使用信号,我通常有一个从 QObject 继承的附加对象。

3. 绘制一个手柄项,并确定要旋转的旋转角度

在下面的示例中,我有一个非常小的矩形作为句柄,您当然可以使用任何您喜欢的 QGraphicsItem。我的方法make_GraphicsItem_draggable采用任何 QGraphicsItem 派生类并使其可拖动。在给定可拖动手柄项目的当前位置和要旋转的项目的变换原点的情况下,确定旋转角度,以及这些位置math.atan2的差异xy坐标。

例子

import math
from PyQt5 import QtCore, QtWidgets

class DraggableGraphicsItemSignaller(QtCore.QObject):

    positionChanged = QtCore.pyqtSignal(QtCore.QPointF)

    def __init__(self):
        super().__init__()

def make_GraphicsItem_draggable(parent):

    class DraggableGraphicsItem(parent):

        def __init__(self, *args, **kwargs):
            """
            By default QGraphicsItems are not movable and also do not emit signals when the position is changed for
            performance reasons. We need to turn this on.
            """
            parent.__init__(self, *args, **kwargs)
            self.parent = parent
            self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges)
            self.signaller = DraggableGraphicsItemSignaller()

        def itemChange(self, change, value):
            if change == QtWidgets.QGraphicsItem.ItemPositionChange:
                self.signaller.positionChanged.emit(value)

            return parent.itemChange(self, change, value)

    return DraggableGraphicsItem

def rotate_item(position):
    item_position = item.transformOriginPoint()
    angle = math.atan2(item_position.y() - position.y(), item_position.x() - position.x()) / math.pi * 180 - 45 # -45 because handle item is at upper left border, adjust to your needs
    print(angle)
    item.setRotation(angle)


DraggableRectItem = make_GraphicsItem_draggable(QtWidgets.QGraphicsRectItem)

app = QtWidgets.QApplication([])

scene = QtWidgets.QGraphicsScene()
item = scene.addRect(0, 0, 100, 100)
item.setTransformOriginPoint(50, 50)

handle_item = DraggableRectItem()
handle_item.signaller.positionChanged.connect(rotate_item)
handle_item.setRect(-40, -40, 20, 20)
scene.addItem(handle_item)

view = QtWidgets.QGraphicsView(scene)
view.setFixedSize(300, 200)
view.show()

app.exec_()

开始(项目 = 大矩形和句柄 = 小矩形)

开始

拖动手柄后旋转(小矩形)

旋转

缺少的一件事:手柄与项目位置没有固定距离(即,您可以将其拖得更远或更近,而不是在一个圆圈中移动)。虽然这不会改变旋转角度,但它看起来并不完美。但这里涵盖了要点,应该让你走上正确的道路。

于 2016-11-08T13:54:34.327 回答