【问题标题】:How to resize polygon by dragging its corners?如何通过拖动角来调整多边形的大小?
【发布时间】:2021-11-24 00:59:43
【问题描述】:

我在 QGraphicsScene 上单击鼠标时保存点,将其附加到列表中,并通过循环遍历列表来创建 QGraphicsPolygonItem。

我使用自定义的 QGraphicsScene,只要有鼠标按下事件,它就会发出位置。代码如下。 (感谢SignalHelper class

class SignalHelper(QObject):
    messageSignal = QtCore.Signal(object)

class Scene(QGraphicsScene):
    def __init__(self, parent=None):
        super(Scene, self).__init__(parent)
        self.helper = SignalHelper()

    def mousePressEvent(self, event):
        self.helper.messageSignal.emit(event.scenePos())

这是我的主窗口的代码。

class main_window(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 500, 500)
        self.pen = QtGui.QPen(QtGui.QColor(0,0,0))                     
        self.pen.setWidth(5)                                             

        self.view = QGraphicsView(self)
        self.scene = Scene()
        self.btn_record_points = QPushButton("Record")
        self.btn_finished = QPushButton("Finished")
        
        self.view.setSceneRect(0, 0, 500,500)
        self.view.setScene(self.scene)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.view)
        vbox.addWidget(self.btn_record_points)
        vbox.addWidget(self.btn_finished)

        self.setLayout(vbox)

        self.point_list = []
        self.record_points = False

        #Signals
        self.btn_record_points.clicked.connect(self.enable_record_points)
        self.btn_finished.clicked.connect(self.create_polygon)
        self.scene.helper.messageSignal.connect(self.draw_points)
        
    def create_polygon(self):
        # Remove ellipses
        drawn_points = self.scene.items()
        for i in drawn_points:
            self.scene.removeItem(i)

        polygon = QGraphicsPolygonItem(QtGui.QPolygonF(self.point_list))
        polygon.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.scene.addItem(polygon)
        self.record_points = False
        self.point_list.clear()

    QtCore.Slot(QtCore.QPointF)
    def draw_points(self, point):
        if self.record_points == True:
            self.point_list.append(point)
            self.scene.addEllipse(point.toTuple()[0], point.toTuple()[1], 1, 1) 

    QtCore.Slot(bool)
    def enable_record_points(self):
        self.record_points = True

这是一个随机多边形的示例:

使用注意事项:

  1. 按“录制”按钮
  2. 在场景中点击多次
  3. 按“完成”按钮

既然创建了多边形,有没有办法通过拖动它的角来调整多边形的大小?

【问题讨论】:

    标签: python pyqt pyside qgraphicsitem


    【解决方案1】:

    通过“拖动其角调整多边形的大小”我想象你想移动多边形的点。

    所以这是一种方法。

    因此,首先使您的多边形可选择,一旦选择了多边形,就遍历多边形的点并在每个点处绘制一个椭圆。存储椭圆、polygon_point_index 映射。

    现在通过遍历mapping_list检查选择了哪个椭圆,然后使用这个椭圆,polygon_index映射来更新多边形的具体点。

    这是一个例子(你可以改进):

    import sys
    from PyQt5 import QtWidgets
    from PyQt5 import QtGui
    from PyQt5 import QtCore
    
    
    class Scene(QtWidgets.QGraphicsScene):
    
        def __init__(self, *args, **kwargs):
            super(Scene, self).__init__(*args, **kwargs)
            self.record_points = True
            self.selected = None  # the selected polygon
            self.points_lst = []  # points that are stored when recording
            self.corner_points = []  # This contains corner point and control point mapping
            self.selected_corner = None
            self.poly_points = [] # points that are stored when resizing (You could instead reuse points_lst)
    
        def record(self):
            self.record_points = True
    
        def removeControlPoints(self):
            """ removes the control points (i,e the ellipse)"""
            for ellipse, _ in self.corner_points:
                self.removeItem(ellipse)
    
            self.corner_points = []
    
        def mousePressEvent(self, event):
            super(Scene, self).mousePressEvent(event)
    
            if self.record_points:
                self.points_lst.append(event.scenePos())
                return
    
            for point in self.corner_points:
                if point[0].contains(event.scenePos()):
                    self.selected_corner = point
                    return
    
            if self.selectedItems():
    
                self.removeControlPoints()
    
                self.selected = self.selectedItems()[0]
                self.poly_points = [self.selected.mapToScene(x) for x in self.selected.polygon()]
    
                for index, point in enumerate(self.poly_points):
                    x, y = point.x(), point.y()
                    ellipse = self.addEllipse(QtCore.QRectF(x - 5, y - 5, 10, 10), brush=QtGui.QBrush(QtGui.QColor("red")))
                    ellipse.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable)
    
                    self.corner_points.append((ellipse, index))
    
            else:
                self.selected = None
                self.removeControlPoints()
                self.corner_points = []
                self.poly_points = []
                self.selected_corner = None
    
        def mouseMoveEvent(self, event) -> None:
            super(Scene, self).mouseMoveEvent(event)
    
            if self.selected_corner:
                self.poly_points[self.selected_corner[1]] = QtCore.QPointF(event.scenePos())
                self.selected.setPolygon(QtGui.QPolygonF(self.poly_points))
    
        def mouseReleaseEvent(self, event) -> None:
            super(Scene, self).mouseReleaseEvent(event)
            self.selected_corner = None
    
        def addPoints(self):  # adds the polygon to the scene
            self.record_points = False
            polygon = self.addPolygon(QtGui.QPolygonF(self.points_lst))
            polygon.setFlags(QtWidgets.QGraphicsItem.ItemIsSelectable)
            self.points_lst = []
    
    
    class MainWindow(QtWidgets.QWidget):
    
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            self.setLayout(QtWidgets.QVBoxLayout())
    
            view = QtWidgets.QGraphicsView()
            scene = Scene()
            view.setScene(scene)
    
            record_btn = QtWidgets.QPushButton(text="Record", clicked=scene.record)
            finish_btn = QtWidgets.QPushButton(text="Finish", clicked=scene.addPoints)
    
            self.layout().addWidget(view)
            self.layout().addWidget(record_btn)
            self.layout().addWidget(finish_btn)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        win = MainWindow()
        win.show()
    
        sys.exit(app.exec_())
    

    输出:

    【讨论】:

      猜你喜欢
      • 2012-01-17
      • 1970-01-01
      • 2014-09-24
      • 2023-03-31
      • 1970-01-01
      • 2017-08-30
      • 2014-07-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多