Reputation: 141
I want to have a QTreeWidget with hierarchical items where one column contains a custom widget. I created a custom widget that contains a QLabel and a QSpinBox in a horizontal layout.
MySlider.py looks like this:
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)
Then I want to create a QTreeWidget where the third column is filled with a MySlider
widget. The application looks like this:
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()
The problem is: the custom widget is not placed in the third column as wished, but is shown in the top-left corner of the window. Has anyone any idea why it goes wrong?
Upvotes: 1
Views: 2018
Reputation: 120578
There are several problems with the definition of the MySlider
class.
Firstly, you should never use self.__class__
with super
. In certain scenarios it can cause an infifnite recursion, and in any case it's completely unnecessary to pass arguments to super
in Python 3.
Secondly, there's no need to create an inner widget for the layout - and it should not be parented to the object that's passed in as the parent
argument (this is what actually causes the widget to be displayed in the wrong place).
Finally, you probably need to make some adjustments to the layout to ensure that the custom widget does not take up too much space, and that its child widgets expand to the appropriate sizes.
Here is how the class should look:
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()
If you'd prefer to have the spin-box expand to fill the whole column, you can omit the last line and do this instead:
# make sure the spin-box fills the whole column
layout.addWidget(self.spinBox1, 1)
Note that in the code above, the child widgets aren't given an explicit parent. Whenever widgets are added to a layout, Qt will automatically reparent them to whichever widget eventually contains the layout.
Upvotes: 1