如何通过拖动角来调整多边形的大小?
How to resize polygon by dragging its corners?
我在 QGraphicsScene 上单击鼠标时保存点,将其附加到列表中,并通过遍历列表创建 QGraphicsPolygonItem。
我使用自定义 QGraphicsScene,只要有鼠标按下事件就会发出位置。代码如下。 (感谢 )
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())
这是我的主要代码 window。
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_())
输出:
我在 QGraphicsScene 上单击鼠标时保存点,将其附加到列表中,并通过遍历列表创建 QGraphicsPolygonItem。
我使用自定义 QGraphicsScene,只要有鼠标按下事件就会发出位置。代码如下。 (感谢
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())
这是我的主要代码 window。
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_())
输出: