用鼠标旋转QGraphicsPixmapItem

时间:2012-06-21 22:02:34

标签: qt rotation pyqt qgraphicsscene

我正在PyQt中编写一个允许用户选择的应用程序 放置在QGraphicsScene上的图像(使用自定义 QGraphicsPixmapItem)。选择后,我想要一个旋转手柄 出现在用户可以用鼠标“抓住”的图像上 旋转,从而旋转QGraphicsPixmapItem。基本上,我在寻找 对于旋转手柄功能,您可以在选择a时进入PowerPoint 形状。这似乎是很多人会做的一个非常基本的功能 已实施,但我在网上找不到任何好的例子。能够 有人指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

让我们首先将问题分成较小的问题然后再组装一切。我在这个解决方案中使用了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_()

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

Start

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

Rotated

缺少一件事:手柄与物品位置没有固定的距离(即,不是以圆形移动,而是可以将其拖得更远或更近)。虽然这不会改变旋转角度,但看起来并不完美。但是这里涉及的要点很重要,应该让你走在正确的轨道上。