在同一个图形场景中加入QGraphicsItem和QPainter。

问题描述 投票:0回答:1

我目前正在使用PyQt5和Graphicscene构建一个交互式画布,目前修改了这些帖子中的代码。

我已经做了两个单独的例子,我想,但到目前为止,我还没有能够将两个合并成一个单一的代码。

第一段代码我在屏幕上点击的位置插入一个节点和相应的边缘。以鼠标左键双击开始和结束。

import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *

class WindowClass(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.view = ViewClass()
        self.setCentralWidget(self.view)

class ViewClass(QGraphicsView):
    def __init__(self, parent=None):
        QGraphicsView.__init__(self, parent)
        self.s = SceneClass()
        self.setScene(self.s)
        self.setRenderHint(QPainter.Antialiasing)

class SceneClass(QGraphicsScene):
    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)

        self.node_start = None
        self.node_end = None
        self.pos = None
        self.pos_end = None

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton and self.node_start is None:
            node = Node()
            self.addItem(node)
            node.setPos(event.scenePos() + QPointF(10, 10))
            self.node_start = node
        else:
            self.node_start = None

    def mouseMoveEvent(self, event):
        super(SceneClass, self).mouseMoveEvent(event)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton and self.node_start:
            "nodo final"
            node = Node()
            self.addItem(node)
            node.setPos(event.scenePos() + QPointF(10, 10))
            self.node_end = node
            edge = Edge(self.node_start, self.node_end)
            self.addItem(edge)
            "nodo final se convierte en nodo inicial"
            self.node_start = self.node_end
        super(SceneClass, self).mousePressEvent(event)

class Node(QGraphicsEllipseItem):
    def __init__(self, rect=QRectF(-20, -20, 20, 20), parent=None):
        QGraphicsEllipseItem.__init__(self, rect, parent)
        self.edges = []
        self.setZValue(1)
        self.setBrush(Qt.darkGray)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)

    def addEdge(self, edge):
        self.edges.append(edge)

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

        if change == QGraphicsItem.ItemPositionHasChanged:
            for edge in self.edges:
                edge.adjust()

        return QGraphicsItem.itemChange(self, change, value)

class Edge(QGraphicsLineItem):
    def __init__(self, source, dest, parent=None):
        QGraphicsLineItem.__init__(self, parent)
        self.source = source
        self.dest = dest
        self.source.addEdge(self)
        self.dest.addEdge(self)
        self.setPen(QPen(Qt.red, 3))
        self.adjust()

    def adjust(self):
        self.prepareGeometryChange()
        self.setLine(QLineF(self.dest.pos() + QPointF(-10, -10), self.source.pos() + QPointF(-10, -10)))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wd = WindowClass()
    wd.show()
    sys.exit(app.exec_())

第二段代码从最后点击鼠标左键的位置到当前鼠标在屏幕上的位置画一条线。

import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt

class MouseTracker(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setMouseTracking(True)

    def initUI(self):
        self.setGeometry(200, 200, 1000, 500)
        self.setWindowTitle('Mouse Tracker')
        self.label = QLabel(self)
        self.label.resize(500, 40)
        self.show()
        self.pos = None
        self.pos_end = None

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.pos_end = event.pos()

    def mouseMoveEvent(self, event):
        self.pos = event.pos()
        self.update()

    def paintEvent(self, event):
        if self.pos and self.pos_end:
            "Estilo de Linea"
            pen = QPen(Qt.red)
            pen.setWidth(3)
            pen.setStyle(Qt.CustomDashLine)
            pen.setDashPattern([10, 10])
            pen.setJoinStyle(Qt.RoundJoin)
            "Objeto de QPainter"
            q = QPainter(self)
            q.setRenderHint(QPainter.Antialiasing, True)
            "Aplicar estilo de Linea"
            q.setPen(pen)
            "Dibujar Linea"
            q.drawLine(self.pos.x(), self.pos.y(), self.pos_end.x(), self.pos_end.y())

app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())

我希望在mi GUI代码中看到的行为是这两个代码的结合,意思是:能够通过鼠标左键插入节点及其对应的边缘,然后当鼠标左键被释放时,从最后插入的节点到屏幕上的当前位置开始第二段代码的QPaint线。我试着把这两段代码连接起来,但是当第一段代码的任何一个类被写入时,paintvent没有被触发,即使ti是自己的类。

python pyqt pyqt5 qgraphicsview qgraphicsscene
1个回答
2
投票

QPainter是用来作画的低级工具,不同的高级工具都用它作为Qt图形框架,但在这种情况下不应该使用它们。

在你的情况下,最好使用这些项目,因为它简化了任务。

class WindowClass(QMainWindow):
    def __init__(self, parent=None):
        super(WindowClass, self).__init__(parent)
        view = QGraphicsView()
        view.setMouseTracking(True)
        view.setRenderHint(QPainter.Antialiasing)
        scene = SceneClass(self)
        view.setScene(scene)
        self.setCentralWidget(view)
        self.resize(640, 480)


class SceneClass(QGraphicsScene):
    def __init__(self, parent=None):
        super(SceneClass, self).__init__(QRectF(-1000, -1000, 2000, 2000), parent)
        self._edge_item = None

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            node = Node()
            node.setPos(event.scenePos())
            self.addItem(node)

            if self._edge_item:
                self._edge_item.dst = node
                self._edge_item = None
            else:
                self._edge_item = Edge()
                self._edge_item.src = node
                self.addItem(self._edge_item)

    def mouseMoveEvent(self, event):
        if self._edge_item:
            self._edge_item.p2 = event.scenePos()
        super(SceneClass, self).mouseMoveEvent(event)


class Node(QGraphicsEllipseItem):
    def __init__(self, rect=QRectF(-10, -10, 20, 20), parent=None):
        super(Node, self).__init__(rect, parent)
        self.edges = []
        self.setZValue(1)
        self.setBrush(Qt.darkGray)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)

    def addEdge(self, edge):
        self.edges.append(edge)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            self.setBrush(Qt.green if value else Qt.darkGray)
        if change == QGraphicsItem.ItemPositionHasChanged:
            for edge in self.edges:
                edge.adjust()
        return super(Node, self).itemChange(change, value)


class Edge(QGraphicsLineItem):
    def __init__(self, parent=None):
        super(Edge, self).__init__(parent)
        self.setPen(QPen(Qt.red, 3))
        self._src = None
        self._dst = None

    @property
    def src(self):
        return self._src

    @src.setter
    def src(self, node):
        self._src = node
        self._src.addEdge(self)
        self.adjust()

    @property
    def dst(self):
        return self._dst

    @dst.setter
    def dst(self, node):
        self._dst = node
        self._dst.addEdge(self)
        self.adjust()

    @property
    def p1(self):
        return self.line().p1()

    @p1.setter
    def p1(self, p):
        line = self.line()
        line.setP1(p)
        self.setLine(line)

    @property
    def p2(self):
        return self.line().p2()

    @p2.setter
    def p2(self, p):
        line = self.line()
        line.setP2(p)
        self.setLine(line)

    def adjust(self):
        self.prepareGeometryChange()
        if self.src:
            self.p1 = self.src.pos()
            self.p2 = self.src.pos()
        if self.dst:
            self.p2 = self.dst.pos()
© www.soinside.com 2019 - 2024. All rights reserved.