在同一个 GraphicsScene 中加入 QGraphicsItem 和 QPainter [英] Join QGraphicsItem and QPainter in same GraphicsScene

查看:57
本文介绍了在同一个 GraphicsScene 中加入 QGraphicsItem 和 QPainter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am currently building an interactive canvas using PyQt5 and Graphicscene, so far modifying the codes found on those posts:

我已经制作了两个我想要的单独示例,但到目前为止我还没有能够将两者合并为一个代码.

I have made two separates examples of what I would like , but so far I have not been able to merge the two into a single code.

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

The first code I inserts a node and corresponding edge in the position clicked on the screen. Begins and ends with a double click of the left button of the mouse.

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_())

第二个代码从最后点击鼠标左键的位置到屏幕上的当前鼠标位置绘制一条线.

The second code paints a line from the last position where the left mouse button was clicked to the current mouse position on the screen.

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从最后一个节点开始的第二行代码插入到屏幕上的当前位置.我试图加入这两个代码,但是在第一个代码的任何类中编写时,paintevent 不会触发,即使 ti 是它自己的类.

The behavior I would like to see in mi GUI code is the union of the two meaning the following: being able to insert node with its corresponding edge by a left mouse click and then when the left mouse click is released start the QPaint line of the second code from the last node insert to the current position on the screen. I have tried to join the two code but the paintevent does not triggered when is written in any of the classes of the first code, even if ti is its own class.

推荐答案

QPainter 是用于绘制的低级工具,不同的高级工具将其用作 Qt 图形框架,但在这种情况下它们不应该是用过.

QPainter is the low-level tool used for painting and the different high-level tools use it as the Qt Graphics Framework, but in this case they should not be used.

在您的情况下,最好使用这些项目,因为它可以简化任务:

In your case it is preferable to use the items since it simplifies the task:

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()

这篇关于在同一个 GraphicsScene 中加入 QGraphicsItem 和 QPainter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆