Я работаю над редактором узлов и в настоящее время создаю свою собственную систему, используя QGraphicsWidget
и QGraphicsScene
. Мне очень удобно использовать QGraphicsGridLayout
в моем классе Node
и просто добавлять подкомпоненты, такие как ввод текста / чисел, метки и т. Д. c в макет. Теперь моя проблема в том, что я хотел бы создать сокет прямо рядом с входом, который должен выглядеть как маленький круг, где можно соединить ребро. В настоящее время это выглядит так:
Однако я не могу заставить сокет быть размещенным на полпути вне Узла. Я попытался нарисовать его в методе 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)