PyQt5 QGraphicsPathItem для рисования QPainter - PullRequest
1 голос
/ 19 апреля 2019

У меня есть путь, который составляет символ, и мне было интересно, может ли этот путь быть нарисован QPainter. Читая документацию, я увидел, что с QPainter связана функция drawPath, но каждый раз, когда я пытаюсь ее реализовать, я получаю сообщение об ошибке QPainter::drawPath: Painter not active.

Поскольку у меня не было успешных попыток, я добавил свернутую рабочую версию своего кода. Это даст вам некоторые основные функции масштабирования и панорамирования наряду с выбором символа и удержанием Shift, чтобы отменить выбор символа.

Мне бы хотелось, чтобы путь изменял цвета, когда он был выбран или наведен на него, и в настоящее время он заполняется, когда он выбран или наведен. В конце концов, я бы хотел, чтобы пользователь мог изменить путь к пунктирной линии или цвету с самого начала.

Спасибо за любые советы и помощь.

Код

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtSvg import *
import sys
from math import sqrt,cos,acos,asin,degrees,pi


class LogObject(QObject):
    hovered = pyqtSignal()
    notHovered = pyqtSignal()

def figAngle(radius,opposite):
    dist = sqrt((radius) ** 2 + (opposite) ** 2)
    angle = degrees(asin(opposite/dist))
    if angle < 0:
        angle = angle + 360
    return angle

def create_path():
    scale = 250
    path = QPainterPath()
    path.addEllipse(QPointF(0,0), 0.0268, 0.0268) # Using QPointF will center it
    startAngle = figAngle(0.0357/scale,0.0045/scale) # Use the scale so that it will adjust as it is scaled
    endAngle = figAngle(0.0357/scale,-0.0092/scale)
    path.moveTo((0.0357+0.0821),0.0045 )
    path.arcTo(QRectF(-0.0357,-0.0357,(0.0357*2),(0.0357*2)),-startAngle,-endAngle)
    path.moveTo(0.0357, -0.0045)
    path.lineTo(0.0357 + 0.0821, -0.0045)
    path.lineTo(0.0357+0.0821,-0.0045-0.0680)
    path.lineTo(0.0357+0.0821+0.1450,-0.0045-0.0680)
    path.lineTo(0.0357+0.0821+0.1450,-0.0045-0.0680+0.1450)
    path.lineTo(0.0357+0.0821,-0.0045-0.0680+0.1450)
    path.lineTo(0.0357+0.0821,-0.0045-0.0680+0.1450-0.0680)
    path.moveTo(0.0357+0.0821+0.0090,-0.0045-0.0680+0.1450-0.0090)

    path.addRect(0.0357+0.0821+0.0090, -0.0045-0.0680+0.1450-0.0090-0.1270, 0.1270, 0.1270)
    tr = QTransform()
    tr.scale(scale, scale)
    path = tr.map(path)
    return path

class Point(QGraphicsPathItem):
    def __init__(self, x, y, r, name):
        super(Point, self).__init__()
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setPath(create_path())
        self.setScale(1)
        self.setRotation(180+r)
        self.setAcceptHoverEvents(True)
        self.log = LogObject()
        self.setPos(x, y)
        self.isSelected = False

    def itemChange(self, change, value):
        if change == self.ItemSelectedChange:
            self.setBrush(QBrush(Qt.green) if value else QBrush(Qt.black))
        return QGraphicsItem.itemChange(self, change, value)

    def hoverEnterEvent(self, event):
        self.setBrush(QColor("red"))
        self.log.hovered.emit()
        QGraphicsItem.hoverMoveEvent(self, event)

    def hoverLeaveEvent(self, event):
        if self.isSelected == True:
            self.setBrush(QBrush(Qt.green))
        else:
            self.setBrush(QColor("black"))
        self.log.notHovered.emit()
        QGraphicsItem.hoverMoveEvent(self, event)


class Viewer(QGraphicsView):
    photoClicked = pyqtSignal(QPoint)
    rectChanged = pyqtSignal(QRect)

    def __init__(self, parent):
        super(Viewer, self).__init__(parent)
        self.setRenderHints(QPainter.Antialiasing)

        self._zoom = 0
        self._empty = True
        self.setScene(QGraphicsScene(self))

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setFrameShape(QFrame.NoFrame)
        self.area = float()
        self.setPoints()
        self.viewport().setCursor(Qt.ArrowCursor)
        QTimer.singleShot(0, self.reset_fit)
        self.selectedItems = []

    def setItems(self):
        self.data = {
            "x": [
                -2414943.8686,
                -2417160.6592,
                -2417160.6592,
                -2416009.9966,
                -2416012.5232,
                -2416012.5232,
            ],
            "y": [
                10454269.7008,
                10454147.2672,
                10454147.2672,
                10453240.2808,
                10455255.8752,
                10455255.8752,

            ],
            "rotation":[
            313.9962,
            43.9962,
            223.9962,
            313.9962,
            43.9962,
            223.9962,
            ]
        }

        for i, (x, y,r) in enumerate(zip(self.data["x"], self.data["y"],self.data["rotation"])):
            p = Point(x, y,r, "Point__" + str(i))
            p.log.hovered.connect(self.hoverChange)
            p.log.notHovered.connect(self.notHoverChange)
            self.scene().addItem(p)

    def setPoints(self):
        self.setItems()
        self.setDragMode(self.ScrollHandDrag)

    def wheelEvent(self, event):
        if event.angleDelta().y() > 0:
            factor = 1.25
            self._zoom += 1
        else:
            factor = 0.8
            self._zoom -= 1
        if self._zoom > 0:
            self.scale(factor, factor)
        elif self._zoom == 0:
            self.reset_fit()
        else:
            self._zoom = 0

    def hoverChange(self):
        self.viewport().setCursor(Qt.PointingHandCursor)

    def notHoverChange(self):
        self.viewport().setCursor(Qt.ArrowCursor)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            singleItem = self.itemAt(event.pos().x(), event.pos().y())
            if singleItem != None:
                if QApplication.keyboardModifiers() == Qt.ShiftModifier: # This will determine if the shift key is depressed
                    if singleItem.isSelected == True:
                        singleItem.setSelected(False)
                        singleItem.isSelected = False
                        self.selectedItems.remove(singleItem)
                elif singleItem.isSelected == False:
                    singleItem.setSelected(True)
                    singleItem.isSelected = True
                    self.selectedItems.append(singleItem)
            return

        elif event.button() == Qt.MidButton:
            self.viewport().setCursor(Qt.ClosedHandCursor)
            self.original_event = event
            handmade_event = QMouseEvent(
                QEvent.MouseButtonPress,
                QPointF(event.pos()),
                Qt.LeftButton,
                event.buttons(),
                Qt.KeyboardModifiers(),
            )
            QGraphicsView.mousePressEvent(self, handmade_event)

        super(Viewer, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.MidButton:
            self.viewport().setCursor(Qt.ArrowCursor)
            handmade_event = QMouseEvent(
                QEvent.MouseButtonRelease,
                QPointF(event.pos()),
                Qt.LeftButton,
                event.buttons(),
                Qt.KeyboardModifiers(),
            )
            QGraphicsView.mouseReleaseEvent(self, handmade_event)

    def reset_fit(self):
        r = self.scene().itemsBoundingRect()
        self.resetTransform()
        self.setSceneRect(r)
        self.fitInView(r, Qt.KeepAspectRatio)
        self._zoom = 0
        self.scale(1, -1)


class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.viewer = Viewer(self)
        VBlayout = QVBoxLayout(self)
        VBlayout.addWidget(self.viewer)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 800, 600)
    window.show()
    sys.exit(app.exec_())

1 Ответ

2 голосов
/ 19 апреля 2019

Вам не нужно использовать QPainter в QGraphicsPathItem, вы должны установить QPen с помощью setPen ().


TL;DR;

QGraphicsPathItem уже имеет QPainter, который должен использоваться только в методе paint (), но в этом случае нет необходимости, существующие QGraphicsItems, такие как QGraphicsRectItem, QGraphicsEllipseItem и т. Д., Не нужны для их использования, посколькуэти методы наследуются от QAbstractGraphicsShapeItem и поддерживают QPen и QBrush с использованием методов setPen () и setBrush () соответственно.

Другая проблема, которую я вижу в вашем коде, заключается в том, что вы используете атрибут isSelected, но вам следуетне делайте этого, уже существует метод с таким именем, поэтому вы должны использовать isSelected ().

Учитывая предыдущее решение:

class Point(QGraphicsPathItem):
    def __init__(self, x, y, r, name):
        super(Point, self).__init__()
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setPath(create_path())
        self.setScale(10)
        self.setRotation(180 + r)
        self.setAcceptHoverEvents(True)
        self.log = LogObject()
        self.setPos(x, y)
        pen = QPen(Qt.red)
        pen.setStyle(Qt.DashLine)
        self.setPen(pen)

    def itemChange(self, change, value):
        if change == self.ItemSelectedChange:
            color = QColor(Qt.green) if value else QColor("black")
            # self.setBrush(color)
            pen = self.pen()
            pen.setColor(color)
            self.setPen(pen)
        return QGraphicsItem.itemChange(self, change, value)

    def hoverEnterEvent(self, event):
        color = QColor("red")
        # self.setBrush(color)
        pen = self.pen()
        pen.setColor(color)
        self.setPen(pen)
        self.log.hovered.emit()
        QGraphicsItem.hoverMoveEvent(self, event)

    def hoverLeaveEvent(self, event):
        color = QColor(Qt.green) if self.isSelected() else QColor("black")
        # self.setBrush(color)
        pen = self.pen()
        pen.setColor(color)
        self.setPen(pen)
        self.log.notHovered.emit()
        QGraphicsItem.hoverMoveEvent(self, event)
...