问题描述
我需要将QGraphicspixmapItem
旋转一圈。也就是说,圆圈必须始终位于图像的左上角,并且当我拖动圆圈时,图像必须旋转。我使用setRotation
设置旋转角度,并使用setTransformOriginPoint
设置旋转点。但是,旋转效果不佳。有人可以指出我正确的方向吗?
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication,QGraphicsView
from PyQt5 import QtGui,QtWidgets,QtCore
import math
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.scene = Scene()
self.view = QGraphicsView(self)
self.setGeometry(10,30,850,600)
self.view.setGeometry(20,22,800,550)
self.setFixedSize(850,600)
self.view.setScene(self.scene)
class Scene(QtWidgets.QGraphicsScene):
def __init__(self,parent=None):
super(Scene,self).__init__(parent)
# other stuff here
self.set_image()
def set_image(self):
image = Image()
self.addItem(image)
image.set_pixmap()
class Image(QtWidgets.QGraphicspixmapItem):
def __init__(self,parent=None):
super(Image,self).__init__(parent)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable,True)
self.setTransformOriginPoint(self.boundingRect().center())
def set_pixmap(self):
pixmap = QtGui.Qpixmap("image.jpg")
self.setpixmap(pixmap)
self.pixmap_controller = pixmapController(self)
self.pixmap_controller.set_pixmap_controller()
class pixmapController(QtWidgets.QGraphicsEllipseItem):
def __init__(self,pixmap):
super(pixmapController,self).__init__(parent=pixmap)
self.pixmap = pixmap
color = QtGui.QColor(0,0)
brush = QtGui.QBrush(color)
self.setBrush(brush)
def set_pixmap_controller(self):
self.setRect(-5,-5,10,10)
def mousepressEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.startPos = event.pos()
def mouseMoveEvent(self,event):
if event.buttons() == QtCore.Qt.LeftButton:
self.finalPos = event.pos()
delta = self.finalPos - self.startPos
item_position = self.pixmap.transformOriginPoint()
angle = math.atan2(item_position.y() - self.finalPos.y(),item_position.x() - self.finalPos.x()) / math.pi * 180 - 45
self.parentItem().setRotation(angle)
self.parentItem().setPos(self.parentItem().pos() + delta)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
解决方法
与上一个问题一样,您必须考虑项目坐标系基于其父级(如果没有,则基于场景)。
您的代码还有两个问题:
- 您要在没有设置像素图的情况下设置转换原点,因此该点将为空(
QPointF()
,如该项目的左上角),因为此时边界rect为空;这将使转换不一致,因为原点始终位于像素图项的左上方,而不是其中心; - 您试图在相同的鼠标移动中同时进行和旋转,并且这些转换在概念上显然不兼容。旋转的概念是绕中心的圆周运动,它固定在旋转的坐标系 中。虽然您可以清楚地使对象具有旋转和平移,但只有一个转换的唯一参考点,但是您不能同时拥有它们;
如果您仍然希望能够使用鼠标移动分别进行这两种转换,则可以使用事件修饰符选择实际应用的转换。在下面的示例中,正常的鼠标移动会引起平移,而在单击时,按住 Ctrl 键将进行旋转。
class Image(QtWidgets.QGraphicsPixmapItem):
# ...
def set_pixmap(self):
pixmap = QtGui.QPixmap("image.jpg")
self.setPixmap(pixmap)
self.pixmap_controller = PixmapController(self)
self.pixmap_controller.set_pixmap_controller()
self.setTransformOriginPoint(self.boundingRect().center())
class PixmapController(QtWidgets.QGraphicsEllipseItem):
# ...
def mousePressEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.startPos = event.pos()
self.origin = self.parentItem().transformOriginPoint()
self.startAngle = math.atan2(
self.origin.y(),self.origin.x()
) / math.pi * 180 - 45
self.isRotating = event.modifiers() == QtCore.Qt.ControlModifier
def mouseMoveEvent(self,event):
if event.buttons() == QtCore.Qt.LeftButton:
self.finalPos = event.pos()
delta = self.finalPos - self.startPos
angle = math.atan2(
self.origin.y() - delta.y(),self.origin.x() - delta.x()
) / math.pi * 180 - 45
if self.isRotating:
self.parentItem().setRotation(
self.parentItem().rotation() + (angle - self.startAngle))
else:
self.parentItem().setPos(self.parentItem().pos() + delta)
一个小建议:应始终出于功能的可重用性和/或代码的可读性而创建函数;由于您始终为椭圆项创建相同的矩形(并且该矩形始终基于父项的坐标系),因此像set_pixmap_controller
之类的专用函数及其相关调用没有用,只需使用{{1 }}中的setRect()
。