+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

在父级外部绘制QGraphicsWidget

发布于2021-01-17 16:47     阅读(892)     评论(0)     点赞(0)     收藏(2)


0

1

2

3

4

我正在使用节点编辑器,目前正在使用QGraphicsWidget创建自己的系统QGraphicsScene我发现QGraphicsGridLayoutNode课堂上使用a非常灵活,只需将诸如文本/数字输入,标签等子组件添加到布局中即可。现在,我的问题是我想在输入旁边创建一个套接字,该套接字应该看起来像一个可以连接边的小圆圈。当前看起来像这样:

我系统的当前外观

但是,我无法将套接字放置在Node之外的中间位置。我尝试用paint()方法绘画它Node,但是当节点移动时,它留下了外部部分的痕迹,并且失去了一些灵活性。实现以下外观的最佳方法是什么?

节点编辑器的图像

以下是我的Node班级和我的Socket班级。

from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import Qt, QRectF
from PyQt5.QtGui import QPainterPath, QBrush, QFont, QColor, QPalette
from PyQt5.QtWidgets import QGraphicsItem, QGraphicsTextItem, QGraphicsWidget, QGraphicsGridLayout, QLabel, \
    QLineEdit, QSizePolicy

from src.gui.widgets.graphics.node_scene import NodeScene
from src.gui.widgets.graphics.socket import Socket, SOCKET_TYPE_FLOAT, SOCKET_TYPE_RGB


class Node(QGraphicsWidget):
    def __init__(self, scene: NodeScene, title: str = "", parent=None):
        super().__init__(parent)

        # define data properties
        self._input_sockets = []

        # define Node properties
        self._scene = scene
        self._width = 200
        self._height = 200
        self._rounding = 5
        self._padding = 8
        self._bg_color = QColor(80, 80, 100, 200)
        self._title_color = Qt.white
        self._title_font = QFont("Corbel", 8)
        self._title_font.setBold(True)
        self._title = title
        self._title_item = None

        # Define socket properties
        self._socket_label_font = QFont("Corbel", 7)
        self._socket_label_palette = QPalette()
        self._socket_label_palette.setColor(QPalette.Background, QColor(0, 0, 0, 0))
        self._socket_label_palette.setColor(QPalette.Foreground, self._title_color)

        # Define layout
        self._layout = QGraphicsGridLayout()
        self._layout.setColumnAlignment(0, Qt.AlignLeft)
        #self._layout.setContentsMargins(*[self._padding] * 4)
        self._layout.setHorizontalSpacing(2.0)
        self._layout.setRowSpacing(0, 16)
        self.setLayout(self._layout)

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        # Try adding an input
        self.add_input(SOCKET_TYPE_FLOAT, "Test input")

        # Initialize title
        self._create_title()
        self.title = self._title

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, value):
        self._title = value
        self._title_item.setPlainText(self._title)

    def _create_title(self):
        self._title_item = QGraphicsTextItem(self)
        self._title_item.setDefaultTextColor(self._title_color)
        self._title_item.setFont(self._title_font)
        self._title_item.setPos(self._padding, 0)
        self._title_item.setTextWidth(self._width - self._padding)

    def boundingRect(self) -> QtCore.QRectF:
        return QRectF(0, 0, self._width, self._height).normalized()

    def paint(self, painter, option, widget=None):
        path_bg = QPainterPath()
        path_bg.addRoundedRect(0, 0, self._width, self._height, self._rounding, 1)
        painter.setPen(Qt.NoPen)  # Disables the border
        painter.setBrush(QBrush(self._bg_color))
        painter.drawPath(path_bg)

    def add_input(self, input_type: str, input_name: str, input_range=(0, 1)):
        if input_type == SOCKET_TYPE_FLOAT:
            socket = Socket()
            self._layout.addItem(Socket(), 1, 0)

        if input_type == SOCKET_TYPE_RGB:
            socket = Socket()
            self._layout.addItem(Socket(), 1, 0)

Socket

from PyQt5.QtCore import Qt, QRectF, QPoint
from PyQt5.QtGui import QPainterPath, QColor, QBrush
from PyQt5.QtWidgets import QGraphicsWidget

SOCKET_TYPE_FLOAT = "type_float"
SOCKET_TYPE_RGB = "type_rgb"


class Socket(QGraphicsWidget):

    def __init__(self, *args):
        super().__init__(*args)

        self._circle_color = QColor(255, 130, 0, 255)
        self._bbox = QRectF(0, 0, 10, 10)
        self._current_edge = None

    def boundingRect(self):
        return self._bbox

    def paint(self, painter, option, widget=None):
        path = QPainterPath()
        path.addEllipse(self._bbox)
        painter.setPen(Qt.black)
        painter.setBrush(QBrush(self._circle_color))
        painter.drawPath(path)

解决方案


您需要为布局设置负边距,但不能使用setContentsMargins()负值,因为QGraphicsLayout会自动将边距归一化为0。

我想出的解决方案是对布局进行子类化,并覆盖getContentsMargins()来返回负边距:

class NegativeMarginsLayout(QGraphicsGridLayout):
    def __init__(self, *margins):
        super().__init__()
        self._margins = margins

    def setContentsMargins(self, *margins):
        self._margins = margins
        self.invalidate()
        self.activate()

    def getContentsMargins(self):
        return self._margins

class Node(QGraphicsWidget):
    def __init__(self, scene: QGraphicsScene, title: str = "", parent=None):
        # ...
        self._layout = NegativeMarginsLayout(-20, 0, 20, 0)

边距以外的布局

请注意,使用QGraphicsLayout可能会导致鼠标事件的碰撞函数出现问题,因此您可能应该重写shape()并返回boundingRect的QPainterPath(可能会使用布局边距进行调整)。另外,您无需创建QPainterPath即可绘制圆角矩形的形状,只需使用即可QPainter.drawRoundedRect

0

1

2

3

4

5

6

7

8



所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接: https://www.pythonheidong.com/blog/article/777277/2e7b5f3912e70f089e6d/

来源: python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

0 0
收藏该文
已收藏

评论内容:(最多支持255个字符)