效果

说明

和之前写的可变形矩形相比,最大的差异是不用限制范围了,椭圆的width和height可以是负数。

代码

#写一个可以移动的椭圆类,可以变型

from PySide6.QtCore import Qt, QRectF,  QPointF
from PySide6.QtGui import QPen, QBrush, QColor
from PySide6.QtWidgets import (QApplication, QGraphicsView, QGraphicsScene,
                               QGraphicsItem, QGraphicsEllipseItem, QMainWindow,
                               QVBoxLayout, QWidget)

class ResizableEllipse(QGraphicsEllipseItem):
    def __init__(self,
                 rect = QRectF(0, 0, 100, 50),
                 pen = QPen(QBrush(QColor('blue')), 5)
                 ):
        super().__init__()
        self.setRect(rect)
        self.setPen(pen)
        self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
        self.setAcceptHoverEvents(True)

        self.selected_point = None
        self.click_pos = None
        self.click_ellipse = None

    def mousePressEvent(self, event):
        self.click_pos = event.pos()      
        rect = self.rect()
        x , y , w, h = rect.x(), rect.y(), rect.width(), rect.height()
        top = QPointF(x + w/2, y)
        right = QPointF(x + w, y + h/2)
        bottom = QPointF(x + w/2, y + h)
        left = QPointF(x, y + h/2)

        if abs(self.click_pos.x() - top.x()) < 5 and abs(self.click_pos.y() - top.y()) < 5:
            self.selected_point = 'top'
           # print("top")
        elif abs(self.click_pos.x() - right.x()) < 5 and abs(self.click_pos.y() - right.y()) < 5:
            self.selected_point = 'right'
        elif abs(self.click_pos.x() - bottom.x()) < 5 and abs(self.click_pos.y() - bottom.y()) < 5:
            self.selected_point = 'bottom'
        elif abs(self.click_pos.x() - left.x()) < 5 and abs(self.click_pos.y() - left.y()) < 5:
            self.selected_point = 'left'
        else:
            self.selected_point = None

        self.click_ellipse = self.rect()
        return super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
		#如果已经设置标志不可移动,则直接返回
		flags = self.flags()
        if ((flags & QGraphicsItem.GraphicsItemFlag.ItemIsMovable) != QGraphicsItem.GraphicsItemFlag.ItemIsMovable):
             return super().mouseMoveEvent(event)
		
        pos = event.pos()
        x_diff = pos.x() - self.click_pos.x()
        y_diff = pos.y() - self.click_pos.y()
        print("x_diff:" + str(x_diff) , "y_diff:" + str(y_diff))    
        rect = QRectF(self.click_ellipse)

        if self.selected_point == None:
            rect.translate(x_diff, y_diff)
        elif self.selected_point == 'top':
            rect.adjust(0,y_diff,0,0)
        elif self.selected_point == 'right':
            rect.adjust(0,0,x_diff,0)
        elif self.selected_point == 'bottom':
            rect.adjust(0,0,0,y_diff)
        elif self.selected_point == 'left':
            rect.adjust(x_diff,0,0,0)

        self.setRect(rect)
        print(rect.x(), rect.y(), rect.width(), rect.height())
        # return super().mouseMoveEvent(event) 这句话不能加


    def hoverMoveEvent(self, event):
        pos = event.pos()
        rect = self.rect()
        x , y , w, h = rect.x(), rect.y(), rect.width(), rect.height()
        top = QPointF(x + w/2, y)
        right = QPointF(x + w, y + h/2)
        bottom = QPointF(x + w/2, y + h)
        left = QPointF(x, y + h/2)
        cursor_shape = Qt.CursorShape.ArrowCursor

        if abs(pos.x() - top.x()) < 5 and abs(pos.y() - top.y()) < 5:
            cursor_shape = Qt.CursorShape.SizeVerCursor
        elif abs(pos.x() - right.x()) < 5 and abs(pos.y() - right.y()) < 5:
            cursor_shape = Qt.CursorShape.SizeHorCursor
        elif abs(pos.x() - bottom.x()) < 5 and abs(pos.y() - bottom.y()) < 5:
            cursor_shape = Qt.CursorShape.SizeVerCursor
        elif abs(pos.x() - left.x()) < 5 and abs(pos.y() - left.y()) < 5:
            cursor_shape = Qt.CursorShape.SizeHorCursor
        else:
            cursor_shape = Qt.CursorShape.ArrowCursor

        self.setCursor(cursor_shape)
        return super().hoverMoveEvent(event)
    
    def hoverLeaveEvent(self, event):
        self.setCursor(Qt.CursorShape.ArrowCursor)
        return super().hoverLeaveEvent(event)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        central = QWidget(self)
        self.setCentralWidget(central)

        self.ellipse = ResizableEllipse()
        scene = QGraphicsScene(0, 0, 300, 300)
        scene.addItem(self.ellipse)
        self.view = QGraphicsView(central)
        self.view.setScene(scene)

        layout = QVBoxLayout(central)
        self.setLayout(layout)
        layout.addWidget(self.view)


def main():
    app = QApplication()
    window = MainWindow()
    window.show()

    app.exec_()

main()