简体   繁体   中英

Filling a drawn path using QPainterPath in pyqt5

I have a QGraphicsView which an image is loaded into. I then made it so you can draw over the image with your pointer with QPainterPath and then the path is closed by connecting the beginning and end points. I am wondering how to have that region then filled after the mouse is released and then make this object selectable but not movable.

I tried using QPaint and filling the path as seen in the addGraphicsItem function.

class GraphicsView(QGraphicsView):
    def __init__(self, parent = None):
        super(GraphicsView, self).__init__(parent)
        self.setGeometry(300, 300, 250, 150)
        self.setScene(GraphicsScene(self))
        self.pixmapItem = QGraphicsPixmapItem() # check if everytime you open a new image the old image is still an item
        self.scene().addItem(self.pixmapItem)
        self.initial_path()

    def initial_path(self):
        self._path = QtGui.QPainterPath()
        pen = QtGui.QPen(QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap)
        self._path_item = self.scene().addPath(self._path, pen)

    @QtCore.pyqtSlot()
    def setImage(self):
        filename, _ = QFileDialog.getOpenFileName(None, "select Image", "", "Image Files (*.png *.jpg *jpg *.bmp)")
        if filename:
            self.image = QPixmap(filename)
            self.pixmapItem.setPixmap(QtGui.QPixmap(filename))

    def mousePressEvent(self, event):
        self.start = event.pos()
        if not self.pixmapItem.pixmap().isNull():
            self._path.moveTo(self.mapToScene(event.pos()))
            self._path_item.setPath(self._path)
        super(GraphicsView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if not self.pixmapItem.pixmap().isNull():
            self._path.lineTo(self.mapToScene(event.pos()))
            self._path_item.setPath(self._path)
        super(GraphicsView, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        self.end = event.pos()
        if not self.pixmapItem.pixmap().isNull():
            self._path.lineTo(self.mapToScene(event.pos()))
            self._path.closeSubpath()
            self._path_item.setPath(self._path)
            self.addGraphicsItem()
            self.initial_path()
        super(GraphicsView, self).mouseReleaseEvent(event)

    def addGraphicsItem(self):
        pixmap = self.pixmapItem.pixmap()
        painter = QPainter(pixmap)
        painter.setRenderHint(QPainter.Antialiasing)
        pen = QPen(QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap)
        brush = QBrush(QColor('green'))
        painter.fillPath(self._path, brush)
        painter.end()

I expected the addGraphicsItem function to then fill in the object but nothing changes.

Instead of using QPainter you can continue to use the QGraphicsPainterPath using the setBrush method you can set the background color, plus you can set the flag QGraphicsItem::ItemIsSelectable to be selectable:

from PyQt5 import QtCore, QtGui, QtWidgets


class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(GraphicsView, self).__init__(parent)
        self.setGeometry(300, 300, 250, 150)
        self.setScene(QtWidgets.QGraphicsScene(self))
        self.pixmapItem = (
            QtWidgets.QGraphicsPixmapItem()
        )  # check if everytime you open a new image the old image is still an item
        self.scene().addItem(self.pixmapItem)
        self._path_item = None

    def initial_path(self):
        self._path = QtGui.QPainterPath()
        pen = QtGui.QPen(
            QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap
        )
        self._path_item = self.scene().addPath(self._path, pen)

    @QtCore.pyqtSlot()
    def setImage(self):
        filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            None, "select Image", "", "Image Files (*.png *.jpg *jpg *.bmp)"
        )
        if filename:
            self.pixmapItem.setPixmap(QtGui.QPixmap(filename))

    def mousePressEvent(self, event):
        start = event.pos()
        if (
            not self.pixmapItem.pixmap().isNull()
            and event.buttons() & QtCore.Qt.LeftButton
        ):
            self.initial_path()
            self._path.moveTo(self.mapToScene(start))
            self._path_item.setPath(self._path)
        super(GraphicsView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if (
            not self.pixmapItem.pixmap().isNull()
            and event.buttons() & QtCore.Qt.LeftButton
            and self._path_item is not None
        ):
            self._path.lineTo(self.mapToScene(event.pos()))
            self._path_item.setPath(self._path)
        super(GraphicsView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        end = event.pos()
        if (
            not self.pixmapItem.pixmap().isNull()
            and self._path_item is not None
        ):
            self._path.lineTo(self.mapToScene(end))
            self._path.closeSubpath()
            self._path_item.setPath(self._path)
            self._path_item.setBrush(QtGui.QBrush(QtGui.QColor("red")))
            self._path_item.setFlag(
                QtWidgets.QGraphicsItem.ItemIsSelectable, True
            )
            self._path_item = None
        super(GraphicsView, self).mouseReleaseEvent(event)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = GraphicsView()
    w.setImage()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM