You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决QGraphicsPolygonItem插入顶点后多边形变形问题

问题分析

原代码大概率是未正确判断点击点是否在多边形线段范围内,或是插入顶点后未同步更新多边形与路径的顶点顺序,导致多边形连接关系错乱、出现变形。

正确实现代码

以下是可直接运行的修复代码,实现点击多边形边缘添加顶点且无变形的功能:

from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsPolygonItem, QGraphicsPathItem
from PyQt5.QtGui import QPolygonF, QPainterPath, QMouseEvent, QPen, QBrush
from PyQt5.QtCore import Qt, QPointF, QLineF
import sys

class CustomGraphicsView(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.polygon_item = None
        self.path_item = None
        self.init_polygon()

    def init_polygon(self):
        # 初始化测试矩形多边形
        polygon = QPolygonF([QPointF(100, 100), QPointF(300, 100), QPointF(300, 300), QPointF(100, 300)])
        self.polygon_item = QGraphicsPolygonItem(polygon)
        self.polygon_item.setPen(QPen(Qt.red, 2))
        self.polygon_item.setBrush(QBrush(Qt.transparent))
        self.scene.addItem(self.polygon_item)

        # 同步创建路径项(虚线显示)
        path = QPainterPath()
        path.addPolygon(polygon)
        path.closeSubpath()
        self.path_item = QGraphicsPathItem(path)
        self.path_item.setPen(QPen(Qt.blue, 1, Qt.DashLine))
        self.scene.addItem(self.path_item)

    def mousePressEvent(self, event: QMouseEvent):
        if event.button() != Qt.LeftButton:
            super().mousePressEvent(event)
            return

        click_pos = self.mapToScene(event.pos())
        polygon = self.polygon_item.polygon()
        closest_edge_idx = -1
        min_distance = float('inf')
        closest_point = QPointF()

        # 遍历所有边,筛选出距离点击点最近的有效线段
        for i in range(polygon.count()):
            p1 = polygon[i]
            p2 = polygon[(i+1) % polygon.count()]
            line = QLineF(p1, p2)
            distance = line.distanceToPoint(click_pos)
            proj_point = line.pointAt(line.percentAt(click_pos))

            # 判断投影点是否在线段范围内(避免点击到边的延长线)
            x_in_range = min(p1.x(), p2.x()) <= proj_point.x() <= max(p1.x(), p2.x())
            y_in_range = min(p1.y(), p2.y()) <= proj_point.y() <= max(p1.y(), p2.y())

            if x_in_range and y_in_range and distance < min_distance:
                min_distance = distance
                closest_edge_idx = i
                closest_point = proj_point

        # 距离阈值10像素,避免误操作
        if closest_edge_idx != -1 and min_distance < 10:
            # 在目标边的后一位插入顶点,保证多边形连接顺序正确
            polygon.insert(closest_edge_idx + 1, closest_point)
            self.polygon_item.setPolygon(polygon)
            # 同步更新路径项
            path = QPainterPath()
            path.addPolygon(polygon)
            path.closeSubpath()
            self.path_item.setPath(path)

        super().mousePressEvent(event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = CustomGraphicsView()
    view.setWindowTitle("添加多边形顶点")
    view.resize(600, 600)
    view.show()
    sys.exit(app.exec_())
关键修复点
  • 限制点击范围:通过判断投影点是否在线段的坐标区间内,避免在边的延长线点击时错误添加顶点。
  • 正确插入顶点:在目标边的索引后一位插入新顶点,严格保持多边形的顶点连接顺序。
  • 同步更新双项:修改QGraphicsPolygonItem后,必须重新生成QGraphicsPathItem的路径,确保两者图形一致。
  • 添加误触防护:设置10像素的距离阈值,过滤远离多边形边的无效点击。

内容的提问来源于stack exchange,提问作者Paul_Dx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:50:00