将自定义小部件添加到 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 都会自动将它们重新设置为最终包含该布局的小部件。
我想要一个带有分层项目的 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 都会自动将它们重新设置为最终包含该布局的小部件。