from PySide6.QtCore import QRect, QPoint, QRectF, Qt
from PySide6.QtGui import QMouseEvent, QBrush, QColor, QPen, QTransform, QGuiApplication
from PySide6.QtWidgets import QGraphicsObject, QGraphicsItem
class ImageBox(QGraphicsObject):
def __init__(self, pixmap):
super().__init__()
self.image = pixmap
self.mousePressPos = None
self.mousePressRect = None
self.setAcceptHoverEvents(True)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.isMirroredHorizontally = False
self.isMirroredVertically = False
self.rotate_op = False
self.rect = self.image.rect()
self.moving = []
self.origin = QPoint()
self.setTransformOriginPoint(self.rect.center())
def getPixmap(self):
return self.image
def mirrorHorizontally(self):
rect = self.boundingRect()
self.isMirroredHorizontally = not self.isMirroredHorizontally
scaleX = -1 if self.isMirroredHorizontally else 1
scaleY = -1 if self.isMirroredVertically else 1
transform = QTransform(scaleX, 0, 0, scaleY, 0, 0)
self.setTransform(transform)
if self.isMirroredHorizontally:
self.moveBy(rect.width(), 0)
else:
self.moveBy(-rect.width(), 0)
def mirrorVertically(self):
rect = self.boundingRect()
self.isMirroredVertically = not self.isMirroredVertically
scaleX = -1 if self.isMirroredHorizontally else 1
scaleY = -1 if self.isMirroredVertically else 1
transform = QTransform(scaleX, 0, 0, scaleY, 0, 0)
self.setTransform(transform)
if self.isMirroredVertically:
self.moveBy(0, rect.height())
else:
self.moveBy(0, -rect.height())
def corners_rect(self) -> list:
""" Return corner rect geometry for each corner"""
size = 10 # Розмір елементів масштабування
size2 = self.rect.width() - 40 # Ширина контейнера
size3 = self.rect.height() - 40 # Висота контейнера
half_size = size / 2 # Половина розміру елементів масштабування
return [
QRect(self.rect.left() - half_size, self.rect.top() - half_size, size, size), # top left
QRect(self.rect.right() - half_size, self.rect.top() - half_size, size, size), # top right
QRect(self.rect.left() - half_size, self.rect.bottom() - half_size, size, size), # bottom left
QRect(self.rect.right() - half_size, self.rect.bottom() - half_size, size, size), # bottom right
QRect(self.rect.left() + 20, self.rect.top() - half_size, size2, size),
# top edge
QRect(self.rect.right() - half_size, self.rect.top() + 20, size, size3),
# right edge
QRect(self.rect.left() + 20, self.rect.bottom() - half_size, size2, size),
# bottom edge
QRect(self.rect.left() - half_size, self.rect.top() + 20, size, size3),
# left edge
]
def boundingRect(self) -> QRectF:
""" Override boundingRect """
return self.rect.adjusted(-10, -10, 10, 10)
def paint(self, painter, option, widget=None):
painter.drawPixmap(self.rect, self.image)
painter.drawRect(self.rect)
point_list = self.corners_rect()
if self.isSelected():
pen = QPen(QColor("#00FFFF")) # Set the color of the border
pen.setWidth(3) # Set the width of the border
painter.setPen(pen)
painter.drawRect(self.rect)
painter.setBrush(QBrush(QColor("#00FFFF")))
painter.setPen(Qt.NoPen)
for count, rect in enumerate(point_list[:4], start=0):
painter.drawEllipse(rect)
self.update()
def mousePressEvent(self, event: QMouseEvent):
""" override mouse Press Event """
point_list = self.corners_rect()
self.moving = [rect.contains(QPoint(event.pos().toPoint())) for rect in point_list]
if any(self.moving):
self.origin = self.rect.topLeft()
else:
super().mousePressEvent(event)
def mouseReleaseEvent(self, event: QMouseEvent):
""" Override mouse release event """
self.moving = [False, False, False, False, False, False, False, False]
super().mouseReleaseEvent(event)
def rotateWithMouse(self, mouse_position):
center = self.rect.center()
angle = math.atan2(mouse_position.y() - center.y(), mouse_position.x() - center.x())
angle = math.degrees(angle)
self.setRotation(angle)
def mouseMoveEvent(self, event: QMouseEvent):
""" Override mouse move event """
if any(self.moving):
# If moving is set from mousePressEvent , change geometry
self.prepareGeometryChange()
pos = event.pos().toPoint()
self.rotate_op = False
if QGuiApplication.keyboardModifiers() == Qt.ShiftModifier:
self.rotate_op = True
self.rotateWithMouse(event.pos())
if self.rotate_op == False:
if self.moving[0] or self.moving[2]: # top left or bottom left
self.rect.setLeft(pos.x())
if self.moving[0] or self.moving[1]: # top left or top right
self.rect.setTop(pos.y())
if self.moving[1] or self.moving[3]: # top right or bottom right
self.rect.setRight(pos.x())
if self.moving[2] or self.moving[3]: # bottom left or bottom right
self.rect.setBottom(pos.y())
if self.moving[4]: # top edge
self.rect.setTop(pos.y())
if self.moving[6]: # bottom edge
self.rect.setBottom(pos.x())
self.rect.setBottom(pos.y())
if self.moving[5]: # right edge
self.rect.setRight(pos.x())
if self.moving[7]: # left edge
self.rect.setLeft(pos.x())
self.rect = self.rect.normalized()
self.update()
return
else:
super().mouseMoveEvent(event)
我有一个主类 QGraphicsView,我将图像添加为 ImageBox(QGraphicsObject) 对象。 ImageBox 有几个 QRect 点,用于调整 ImageBox 的大小。我在按下“Shift”按钮时向mouseMoveEvent方法添加了旋转,但结果是,当移动光标时,QGraphicsObject不断颤抖或将旋转返回到几毫秒前的位置,总而言之——不稳定。我想解决这个问题。
您没有考虑两个重要方面:
rotation()
; def rotateWithMouse(self, mouse_position):
center = self.rect.center()
point = self.corners_rect()[self.moving.index(True)]
pointAngle = math.degrees(math.atan2(
point.y() - center.y(), point.x() - center.x()))
angle = math.degrees(math.atan2(
mouse_position.y() - center.y(), mouse_position.x() - center.x()))
self.setRotation(self.rotation() + (angle - pointAngle))
另请注意,您需要注意以下事项:
transformOriginPoint
更新到 new 中心;boundingRect()
应该始终返回 QRectF,但是您返回的是 QImage.rect()
,它是一个基本(基于整数)QRect;将其更改为 QRectF(self.rect.adjusted(-10, -10, 10, 10))
;prepareGeometryChange()
,而不是在应用变换(如旋转)时调用;update
内调用paint()
,因为这会导致间接递归(安排不必要的重画);