将自定义小部件添加到 PyQt5 中的 QTreeWidget 列

Add custom widget to a QTreeWidget column in PyQt5

我想要一个带有分层项目的 QTreeWidget,其中一列包含自定义小部件。我创建了一个自定义小部件,其中包含水平布局中的 QLabel 和 QSpinBox。

MySlider.py 看起来像这样:

from PyQt5 import QtWidgets 
from PyQt5 import QtCore 
from PyQt5.Qt import Qt 
import sys

class MySlider(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(self.__class__, self).__init__(parent)
        
        self.horizontalLayoutWidget = QtWidgets.QWidget(parent)
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)

        self.label = QtWidgets.QLabel(self.horizontalLayoutWidget)
        self.label.setText('Spinbox:')
        self.spinBox1 = QtWidgets.QSpinBox(self.horizontalLayoutWidget)

        self.horizontalLayout.addWidget(self.label)
        self.horizontalLayout.addWidget(self.spinBox1)

然后我想创建一个 QTreeWidget,其中第三列填充了一个 MySlider 小部件。该应用程序如下所示:

import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QAbstractItemView
from MySlider import MySlider

def main():
    _translate = QtCore.QCoreApplication.translate
    app = QtWidgets.QApplication(sys.argv)
    tree = QtWidgets.QTreeWidget()
    tree.setColumnCount(3)
    headerItem = QtWidgets.QTreeWidgetItem()
    headerItem.setText(0, _translate("MainWindow", "md-name"))
    headerItem.setText(1, _translate("MainWindow", "md_value"))
    headerItem.setText(2, _translate("MainWindow", "others"))
    tree.setHeaderItem(headerItem)

    parent = QtWidgets.QTreeWidgetItem(tree)
    parent.setText(0, "Parent 1")
    parent.setText(1, "")
    parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsEditable)

    for x in range(3):
        child = QtWidgets.QTreeWidgetItem(parent)
        child.setFlags(child.flags() | Qt.ItemIsEditable)
        child.setText(0, "Child {}".format(x))
        line_edit = QtWidgets.QLineEdit(tree)

        rs = MySlider(tree)
        tree.setItemWidget(child, 1, line_edit)
        tree.setItemWidget(child, 2, rs)

    tree.setEditTriggers(QAbstractItemView.AllEditTriggers)
    tree.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

问题是:自定义小部件没有按要求放在第三列,而是显示在window的左上角。有谁知道为什么会出错?

MySlider class 的定义有几个问题。

首先,你不应该将 self.__class__super 一起使用。在某些情况下,它可能会导致无限递归,并且在任何情况下都完全没有必要将参数传递给 Python 中的 super 3.

其次,无需为布局创建内部小部件 - 并且它不应作为作为 parent 参数传入的对象的父级(这实际上导致显示小部件在错误的地方)。

最后,您可能需要对布局进行一些调整,以确保自定义小部件不会占用太多空间space,并确保其子小部件扩展到适当的大小。

class 应该是这样的:

class MySlider(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QtWidgets.QHBoxLayout(self)
        # keep only the default margin on the left
        layout.setContentsMargins(-1, 0, 0, 0)
        self.label = QtWidgets.QLabel()
        self.label.setText('Spinbox:')
        self.spinBox1 = QtWidgets.QSpinBox()
        # make sure the spin-box doesn't get too small
        self.spinBox1.setMinimumWidth(80)
        layout.addWidget(self.label)
        layout.addWidget(self.spinBox1)
        # don't allow the spin-box to exapnd too much
        layout.addStretch()

如果您希望 spin-box 展开以填满整个列,您可以省略最后一行并改为这样做:

        # make sure the spin-box fills the whole column
        layout.addWidget(self.spinBox1, 1)
        

请注意,在上面的代码中,子窗口小部件未指定明确的父窗口小部件。每当将小部件添加到布局时,Qt 都会自动将它们重新设置为最终包含该布局的小部件。