Turn QGraphicsPixmapItem with the mouse

I am writing an application in PyQt that will allow users to select images placed on a QGraphicsScene (using a custom QGraphicsPixmapItem ). Once selected, I would like the rotation knob on the image that the user can β€œgrab” with the mouse and rotate, thereby rotating the QGraphicsPixmapItem . Basically, I'm looking for the manual rotation function that you get in PowerPoint when you select a form. This seems like a really basic feature that many people have implemented, but I cannot find good examples on the Internet. Can someone point me in the right direction?

+4
source share
1 answer

Let me first divide the problem into smaller ones, and then reassemble everything again. I am using PyQt5 in this solution.

1. Turn the QGraphicsItem

To do this, you need to set the rotation angle in degrees using setRotation for the element. The rotation will be around the point indicated by setTransformOriginPoint . You can usually take the center of the figure. If you do not specify this point, the upper left corner of the figure is usually taken.

2. Drag QGraphicsItem

For performance reasons, QGraphicsItems cannot move or post position changes to the event framework. By setting the appropriate flags QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges , you can change this. In addition, QGraphicsItem does not inherit from QObject , so for using signals, I usually have an extra object that inherits from QObject.

3. Draw a pen element and determine the angle of rotation for rotation

In the example below, I have a very small rectangle as a handle, you can, of course, use any QGraphicsItem you like. My make_GraphicsItem_draggable method accepts any derived QGraphicsItem class and makes it draggable. Use math.atan2 and the differences in the x and y coordinates of these positions to determine the rotation angle specified by the current position of the handle to be moved and to start the transformation of the element to be rotated.

Example

 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_() 

Start (item = large rectangle and handle = small rectangle)

Start

Rotates after dragging the handle (small rectangle)

To turn

One thing that is missing: the handle does not have a fixed distance to the position of the position (i.e., instead of moving in a circle, you can drag it further or closer). Although this does not change the angle of rotation, it does not look perfect. But the main points here are considered and should put you on the right track.

+1
source

All Articles