Issue
I save points upon clicking mouse on a QGraphicsScene, append it on a list, and create a QGraphicsPolygonItem by looping through the list.
I use a custom QGraphicsScene which emits position whenever there is a mouse press event. The code is as below. (Credits for 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())
Here is the code for my main 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
Here is an example of a random Polygon:
Note on how to use:
- Press "Record" button
- Click a number of times on the Scene
- Press "Finsihed" button
Now that the Polygon is created, is there a way to resize the Polygon by dragging its corners?
Solution
By "resize the Polygon dragging its corners" I'm imagining you want to move the polygon's points around.
So here is one approach.
So, first make your polygon selectable, once the polygon is selected iterate through the polygon's points and draw an ellipse at each point. Store the ellipse, polygon_point_index mapping.
Now check which ellipse is selected by iterating through the mapping_list, then use this ellipse, polygon_index mapping to update the specific point of the polygon.
here is an example (which you may improve):
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_())
output:
Answered By - Art
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.