在 pyqt5 中创建自定义小部件
Creating custom widget in pyqt5
我知道有专门针对此主题的答案,但我正在尝试创建如下所示的节点小部件
这是我试过的代码。
from PyQt5.QtWidgets import *
class NNodeLayout(QWidget):
def __init__(self, container):
super(NNodeLayout, self).__init__(container)
self.node_frame = QFrame(container)
self.node_frame.setFrameShape(QFrame.StyledPanel)
self.node_frame.setStyleSheet('background-color: blue')
self.node_frame.setMinimumSize(50, 50)
self.node_frame_layout = QVBoxLayout()
self.node_frame_grid_layout = QGridLayout()
self.node_frame_layout.setSpacing(0)
self.node_frame_layout.setContentsMargins(0, 0, 0, 0)
self.node_frame_grid_layout.setContentsMargins(5, 0, 5, 0)
self.node_frame_layout.addWidget(QLabel('hello: '))
self.node_frame_layout.addLayout(self.node_frame_grid_layout)
self.node_frame.setLayout(self.node_frame_layout)
def n_label(self, lbl_name):
print(lbl_name)
lbl = QLabel(lbl_name)
lbl.setStyleSheet('background-color:blue')
self.node_frame_grid_layout.addWidget(lbl)
def n_input(self, place_holder = ""):
text_input = QLineEdit()
text_input.placeholderText(place_holder)
self.node_frame_grid_layout.addWidget(text_input)
def n_input_point_shape_color(self):
pass
def n_top_bar(self):
pass
def n_move(self, x, y):
self.node_frame.move(x, y)
def n_resize(self, width, height):
self.node_frame.resize(width, height)
def n_geometry(self):
return self.node_frame.geometry()
我需要添加那些标记为红色的插座以显示在文本旁边
遗憾的是,您不能直接从 child 小部件中绘制 parent。或者,更好的是,你可以,但如果你有很多 children,它可能会导致一些性能问题,因为每个 child 都会请求在 parent 上重新绘制,这并不好。
另一方面,您的方法存在一些问题:不仅您的 NNodeLayout 不是 布局,而且您实际上并没有使用它,因为您正在添加 另一个小部件(框架)。
最简单的解决方案是创建一个包含 2 个嵌套垂直布局的 QFrame 子类,并重新实现 paint 事件。
class NodeFrame(QFrame):
_margin = 4
_styleSheet = '''
NodeFrame {{
border: 1px solid white;
border-radius: {0}px;
background: #3f3f3f;
margin: {0}px;
}}
QWidget {{
color: white;
}}
QLineEdit {{
color: palette(text);
}}
'''
def __init__(self, parent=None):
super().__init__(parent)
layout = QVBoxLayout(self)
self.headerLayout = QVBoxLayout()
layout.addLayout(self.headerLayout)
self.contentLayout = QVBoxLayout()
layout.addLayout(self.contentLayout)
self.options = []
self.setMargin(self._margin)
def setMargin(self, margin):
self._margin = max(4, margin)
self.setStyleSheet(self._styleSheet.format(self._margin))
def addHeaderWidget(self, widget):
self.headerLayout.addWidget(widget)
def removeHeaderWidget(self, widget):
self.headerLayout.removeWidget(widget)
def addOption(self, widget, color=Qt.white):
self.insertOption(-1, widget, color)
def insertOption(self, index, widget, color=Qt.white):
if index < 0:
index = self.contentLayout.count()
self.contentLayout.insertWidget(index, widget)
self.options.insert(index, (widget, color))
def removeOption(self, index):
widget, color = self.options.pop(index)
self.contentLayout.removeWidget(widget)
widget.deleteLater()
self.update()
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.darkGray)
for label, color in self.options:
geo = label.geometry()
top = geo.y() + geo.height() / 2 - self._margin
qp.setBrush(color)
qp.drawEllipse(0, top, self._margin * 2, self._margin * 2)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = NodeFrame()
w.addHeaderWidget(QLabel('I am a header'))
w.addOption(QLabel('Test 1'), Qt.green)
w.addOption(QLabel('Test 2'), Qt.white)
w.addOption(QLineEdit('Hello'), QColor('orange'))
w.show()
sys.exit(app.exec_())
我知道有专门针对此主题的答案,但我正在尝试创建如下所示的节点小部件
这是我试过的代码。
from PyQt5.QtWidgets import *
class NNodeLayout(QWidget):
def __init__(self, container):
super(NNodeLayout, self).__init__(container)
self.node_frame = QFrame(container)
self.node_frame.setFrameShape(QFrame.StyledPanel)
self.node_frame.setStyleSheet('background-color: blue')
self.node_frame.setMinimumSize(50, 50)
self.node_frame_layout = QVBoxLayout()
self.node_frame_grid_layout = QGridLayout()
self.node_frame_layout.setSpacing(0)
self.node_frame_layout.setContentsMargins(0, 0, 0, 0)
self.node_frame_grid_layout.setContentsMargins(5, 0, 5, 0)
self.node_frame_layout.addWidget(QLabel('hello: '))
self.node_frame_layout.addLayout(self.node_frame_grid_layout)
self.node_frame.setLayout(self.node_frame_layout)
def n_label(self, lbl_name):
print(lbl_name)
lbl = QLabel(lbl_name)
lbl.setStyleSheet('background-color:blue')
self.node_frame_grid_layout.addWidget(lbl)
def n_input(self, place_holder = ""):
text_input = QLineEdit()
text_input.placeholderText(place_holder)
self.node_frame_grid_layout.addWidget(text_input)
def n_input_point_shape_color(self):
pass
def n_top_bar(self):
pass
def n_move(self, x, y):
self.node_frame.move(x, y)
def n_resize(self, width, height):
self.node_frame.resize(width, height)
def n_geometry(self):
return self.node_frame.geometry()
我需要添加那些标记为红色的插座以显示在文本旁边
遗憾的是,您不能直接从 child 小部件中绘制 parent。或者,更好的是,你可以,但如果你有很多 children,它可能会导致一些性能问题,因为每个 child 都会请求在 parent 上重新绘制,这并不好。
另一方面,您的方法存在一些问题:不仅您的 NNodeLayout 不是 布局,而且您实际上并没有使用它,因为您正在添加 另一个小部件(框架)。
最简单的解决方案是创建一个包含 2 个嵌套垂直布局的 QFrame 子类,并重新实现 paint 事件。
class NodeFrame(QFrame):
_margin = 4
_styleSheet = '''
NodeFrame {{
border: 1px solid white;
border-radius: {0}px;
background: #3f3f3f;
margin: {0}px;
}}
QWidget {{
color: white;
}}
QLineEdit {{
color: palette(text);
}}
'''
def __init__(self, parent=None):
super().__init__(parent)
layout = QVBoxLayout(self)
self.headerLayout = QVBoxLayout()
layout.addLayout(self.headerLayout)
self.contentLayout = QVBoxLayout()
layout.addLayout(self.contentLayout)
self.options = []
self.setMargin(self._margin)
def setMargin(self, margin):
self._margin = max(4, margin)
self.setStyleSheet(self._styleSheet.format(self._margin))
def addHeaderWidget(self, widget):
self.headerLayout.addWidget(widget)
def removeHeaderWidget(self, widget):
self.headerLayout.removeWidget(widget)
def addOption(self, widget, color=Qt.white):
self.insertOption(-1, widget, color)
def insertOption(self, index, widget, color=Qt.white):
if index < 0:
index = self.contentLayout.count()
self.contentLayout.insertWidget(index, widget)
self.options.insert(index, (widget, color))
def removeOption(self, index):
widget, color = self.options.pop(index)
self.contentLayout.removeWidget(widget)
widget.deleteLater()
self.update()
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.darkGray)
for label, color in self.options:
geo = label.geometry()
top = geo.y() + geo.height() / 2 - self._margin
qp.setBrush(color)
qp.drawEllipse(0, top, self._margin * 2, self._margin * 2)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = NodeFrame()
w.addHeaderWidget(QLabel('I am a header'))
w.addOption(QLabel('Test 1'), Qt.green)
w.addOption(QLabel('Test 2'), Qt.white)
w.addOption(QLineEdit('Hello'), QColor('orange'))
w.show()
sys.exit(app.exec_())