У меня есть сцена, в которой я хотел бы провести линию между двумя точками (нажатие мыши должно быть начальной точкой, а отпускание мыши - конечной точкой) с использованием QPainterpath.

Вот демонстрация того, как я хочу, чтобы это было.

enter image description here

Вот что происходит с моим текущим кодом.

enter image description here

Ниже приведен код, который я пробовал

import sys
from PyQt5 import QtWidgets, QtCore, QtGui

class Scene(QtWidgets.QGraphicsScene):

    def __init__(self, *args, **kwargs):
        super(Scene, self).__init__(*args, **kwargs)
        self.point = QtCore.QPointF(0.0, 0.0)

        self.path = QtGui.QPainterPath()

        self.start_point = None
        self.end_point = None

        self.start = False

    def mousePressEvent(self, event):

        self.start_point = event.scenePos()
        self.start = True
        self.path = QtGui.QPainterPath(self.start_point)
        # self.addLine(self.line.setP1(self.start_point))

        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):

        if self.start:
            self.path.lineTo(event.scenePos())
            # self.path.moveTo(event.scenePos())
            self.addPath(self.path, QtGui.QPen(QtCore.Qt.red))

        super(Scene, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):

        if self.start:
            print(self.path)
            self.path.lineTo(event.scenePos())
            # self.path.moveTo(event.scenePos())
            self.addPath(self.path, QtGui.QPen(QtCore.Qt.red))
            self.start = False

        super(Scene, self).mouseReleaseEvent(event)

def main():
    app = QtWidgets.QApplication(sys.argv)

    view = QtWidgets.QGraphicsView()
    view.setRenderHint(QtGui.QPainter.Antialiasing)

    view.setMouseTracking(True)
    scene = Scene()

    view.setScene(scene)
    view.show()
    
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
0
JacksonPro 19 Янв 2021 в 14:52

2 ответа

Лучший ответ

Каждый раз, когда используется lineTo, создается новая линия, где начальная точка - это последняя добавленная точка, а конечная точка - это та, которая передается функции, поэтому вы видите кривые, поскольку они являются объединением этих линий. Решение состоит в том, чтобы иметь 2 переменные, которые хранят начальную и конечную точки и обновляются при необходимости, а затем использовать эту информацию для обновления QGraphicsPathItem, а не QPainterPath. Та же концепция может быть применена к QGraphicsLineItem с QLineF.

class Scene(QtWidgets.QGraphicsScene):
    def __init__(self, *args, **kwargs):
        super(Scene, self).__init__(*args, **kwargs)

        self.path_item = self.addPath(QtGui.QPainterPath())

        self.start_point = QtCore.QPointF()
        self.end_point = QtCore.QPointF()

    def mousePressEvent(self, event):
        self.start_point = event.scenePos()
        self.end_point = self.start_point
        self.update_path()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.end_point = event.scenePos()
            self.update_path()
        super(Scene, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self.end_point = event.scenePos()
        self.update_path()
        super(Scene, self).mouseReleaseEvent(event)

    def update_path(self):
        if not self.start_point.isNull() and not self.end_point.isNull():
            path = QtGui.QPainterPath()
            path.moveTo(self.start_point)
            path.lineTo(self.end_point)
            self.path_item.setPath(path)
2
eyllanesc 19 Янв 2021 в 14:11

Спасибо @eyllanesc всем, кто пытается достичь этого с помощью QLineF и QGraphicsLineItem вот код.

import sys
from PyQt5 import QtWidgets, QtCore, QtGui


class Scene(QtWidgets.QGraphicsScene):
    def __init__(self, *args, **kwargs):
        super(Scene, self).__init__(*args, **kwargs)

        self.setSceneRect(QtCore.QRectF(0, 0, 500, 500))

        self.line = None
        self.graphics_line = None

        self.start_point = QtCore.QPointF()
        self.end_point = QtCore.QPointF()

    def mousePressEvent(self, event):
        self.start_point = event.scenePos()
        self.end_point = self.start_point

        self.line = QtCore.QLineF(self.start_point, self.end_point)
        self.graphics_line = QtWidgets.QGraphicsLineItem(self.line)

        self.update_path()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.end_point = event.scenePos()
            self.update_path()
        super(Scene, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self.end_point = event.scenePos()
        self.update_path()

        super(Scene, self).mouseReleaseEvent(event)

    def update_path(self):
        if not self.start_point.isNull() and not self.end_point.isNull():
            self.line.setP2(self.end_point)
            self.graphics_line.setLine(self.line)
            self.addItem(self.graphics_line)


def main():
    app = QtWidgets.QApplication(sys.argv)

    view = QtWidgets.QGraphicsView()
    view.setRenderHint(QtGui.QPainter.Antialiasing)

    view.setMouseTracking(True)
    scene = Scene()

    view.setScene(scene)
    view.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

0
JacksonPro 20 Янв 2021 в 13:09