如何在同一个 window 上绘制两个对象?

How to draw both object on the same window?

序言:下面表示的两个对象都在同一个window。

我遇到了无法更新的问题 我遇到与 self.setGeometry(x,y,w,h) 函数相关的问题。所以我想要实现的是多个矩形,并行渲染,单击时每个矩形都有一条线突出它们的矩形。 (虽然创建连接器不是本主题的重点)。

在这种情况下,我将 rect A 和 rect B 一起渲染。 Rect A有一条线突出到鼠标所在的位置。

(obj A)           (obj B)
 ____              ____
|    |            |    |
|  \ |            |    |
 ---\              ----
     \
     (Mouse)

我要实现的目标的示例代码。

# File: connectors.py
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget

class Connector(QWidget):

    def __init__(self, rect: List[int]):
        super().__init__()
        self.setGeometry(0, 0, 1920, 1080)
        self.rect = rect
        self.clicked = False

        self.begin = QPoint(rect[0], rect[1])
        self.end = QPoint(0,0)

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        qp.setPen(Qt.red)
        qp.drawRect(*self.rect)

        if self.clicked:
            qp = QPainter()
            qp.begin(self)
            qp.setPen(Qt.red)
            qp.drawLine(self.begin, self.end)
        self.update()

    def mousePressEvent(self, event):
        if event.button() == 1:
            self.clicked = True
            self.end = event.pos()

    def mouseMoveEvent(self, event):
        if self.clicked:
            self.end = event.pos()

    def mouseReleaseEvent(self, event):
        if event.button() == 1:
            self.clicked = False
            self.end = event.pos()

# File: main.py
scene = QGraphicsScene()
scene.addWidget( Connector((400, 400, 100, 100)) )
scene.addWidget( Connector((400, 600, 100, 100)) )

但我最终得到的是 PyQt 在屏幕上显示最上面的对象,因此只显示一个对象,但是我还尝试最小化引导突出线的几何形状, 单击时,在边框上切断。

解释:

在您的情况下,它有 2 个小部件,您可以在其中绘制矩形,其中一个位于另一个之上,因此您只会看到其中一个:上面的那个。

解决方案:

Qt GraphicsView Framework(QGraphicsView、QGraphicsScene、QGraphicsXItem 等)的工作方式不同,并且不直接使用绘画,因为它们提供了实现所有功能的基本项目,因此在这种情况下,您必须将 QGraphicsRectItem 与 QGraphicsLineItem 一起使用并修改它QGraphicsView的信息。

综合以上,解决方案是:

import sys

from PyQt5.QtCore import QRectF, Qt
from PyQt5.QtWidgets import (
    QApplication,
    QGraphicsLineItem,
    QGraphicsRectItem,
    QGraphicsScene,
    QGraphicsView,
)


class RectItem(QGraphicsRectItem):
    def __init__(self, rect, parent=None):
        super().__init__(parent)
        self.setRect(QRectF(*rect))
        self.setPen(Qt.red)
        self._line_item = QGraphicsLineItem(self)
        self.line_item.setPen(Qt.red)
        l = self.line_item.line()
        l.setP1(self.rect().topLeft())
        l.setP2(self.rect().topLeft())
        self.line_item.setLine(l)
        self.line_item.hide()

    @property
    def line_item(self):
        return self._line_item

    def move_line_to(self, sp):
        lp = self.mapFromScene(sp)
        l = self.line_item.line()
        l.setP2(lp)
        self.line_item.setLine(l)


class GraphicsView(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setScene(QGraphicsScene())

        self.scene().addItem(RectItem((400, 400, 100, 100)))
        self.scene().addItem(RectItem((400, 600, 100, 100)))

    def mousePressEvent(self, event):
        vp = event.pos()
        sp = self.mapToScene(vp)
        self.move_lines(sp)
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        vp = event.pos()
        sp = self.mapToScene(vp)
        self.move_lines(sp)
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        for item in self.items():
            if isinstance(item, RectItem):
                item.line_item.hide()
        super().mouseReleaseEvent(event)

    def move_lines(self, sp):
        for item in self.items():
            if isinstance(item, RectItem):
                item.line_item.show()
                item.move_line_to(sp)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = GraphicsView()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())