python - 如何通过拖动角来调整多边形的大小?
问题描述
我在 QGraphicsScene 上单击鼠标时保存点,将其附加到列表中,并通过循环遍历列表来创建 QGraphicsPolygonItem。
我使用自定义的 QGraphicsScene,只要有鼠标按下事件,它就会发出位置。代码如下。(SignalHelper 类的学分)
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
这是一个随机多边形的示例:
使用注意事项:
- 按“录制”按钮
- 在场景上单击多次
- 按“完成”按钮
现在创建了多边形,有没有办法通过拖动它的角来调整多边形的大小?
解决方案
通过“拖动其角调整多边形的大小”,我想象您想要移动多边形的点。
所以这是一种方法。
因此,首先使您的多边形可选择,一旦选择了多边形,迭代多边形的点并在每个点处绘制一个椭圆。存储椭圆、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_())
输出:
推荐阅读
- json - Swift JSON 到模型类
- javascript - 如何在节点处将 HTML 代码添加到 D3 树形图?
- node.js - 使用 Azure Active Directory 应用程序进行 OAuth 身份验证
- javascript - 如何将此动态ajax函数转换为vue js
- ios - 计算应用程序错误
- apple-push-notifications - Wnat 通过 Servicestack api 使用 APNS 发送推送通知
- javascript - JS .click() 触发器不起作用
- python - matplotlib:如何清楚地显示所有特征(大约 150 个)
- python - `yield` 在烧瓶中的整个解析过程中
- jquery - 在 jQuery 中识别继承的 css 类