4

Thanks to this thread, I'm able to add widgets to 2nd or later column of QAbstractItemView (in my example QTreeView) of top level items of a view.

But is it possible to add widgets to the children items?

Here's what I've tried which partly went well:

#!/usr/bin/env python
import os

from PyQt4.QtCore import QModelIndex, Qt
from PyQt4.QtGui import QApplication, QItemSelectionModel, \
                        QPushButton, QStandardItem, \
                        QStandardItemModel, QTreeView
from PyQt4.uic import loadUi


class PrvTreeviewNest(QTreeView):
    def __init__(self):
        super(PrvTreeviewNest, self).__init__()

        loadUi('/home/user/yourproject/resource/treeview_nest.ui')

        # row can be 0 even when it's more than 0.
        self._datamodel = QStandardItemModel(0, 2)
        self.setModel(self._datamodel)

        for i in range(4):
            self._add_widget(i + 1)

        self.show()

    def _add_widget(self, n):
        std_item = QStandardItem('{}th item'.format(n))
        self._datamodel.setItem(n, 0, std_item)

        node_widget = QPushButton('{}th button'.format(n))
        qindex_widget = self._datamodel.index(n, 1, QModelIndex())
        self.setIndexWidget(qindex_widget, node_widget)

        if n == 2:
            std_item_child = QStandardItem('child')
            std_item.appendRow(std_item_child)

            node_widget_child = QPushButton('petit button')
            qindex_widget_child = self._datamodel.index(n, 1, QModelIndex())
            self.setIndexWidget(qindex_widget_child, node_widget_child)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    # window = TreeviewWidgetSelectProve()
    window = PrvTreeviewNest()
    # window = TreeviewWidgetSelectProve()
    window.resize(320, 240)
    # window.show();
    window.setWindowTitle(
         QApplication.translate("toplevel", "Top-level widget"))
    # window.add_cols()

    sys.exit(app.exec_())

treeview_nest.ui is available.

You see in the image below that the item child doesn't show a button and its parent's button is overwritten. Apparently I have no idea how to write a code for it.

enter image description here


Update) I figured out how to add widget to children. Tricky enough, using QStandardItem.insertRow combined with index does the work. In my sample code above, replace _add_widget with the following:

    def _add_widget(self, n):
        item_toplevel = QStandardItem('{}th item'.format(n))
        self._datamodel.setItem(n, 0, item_toplevel)

        widget_toplevel = QPushButton('{}th button'.format(n))
        qindex_toplevel = self._datamodel.index(n, 1, QModelIndex())
        self.setIndexWidget(qindex_toplevel, widget_toplevel)

        if n == 2:
            item_child_col0 = QStandardItem('child col0')
            item_child_col1 = QStandardItem('child col1')
            #item_toplevel.appendRow(item_child_col0)

            item_toplevel.insertRow(0, [item_child_col0, item_child_col1])

            widget_child = QPushButton('child widget')
            qindex_child = item_child_col1.index()
            self.setIndexWidget(qindex_child, widget_child)

I'm sure this is NOT the best/ideal designed way but seems to work for me. I came up with after inspired by @Phlucious's answer. Thanks!

enter image description here

Community
  • 1
  • 1
IsaacS
  • 3,551
  • 6
  • 39
  • 61

1 Answers1

2

Your mistake is on this line:

qindex_widget_child = self._datamodel.index(n, 1, QModelIndex())
self.setIndexWidget(qindex_widget_child, node_widget_child)

It's giving you the index on row 2 column 1 of the model, which is the "2th item", not your child. Your child is on row 1 column 1 of std_item. In Qt, especially in QStandardItemModel, Children are stored relative to their parent, not relative to the model.

I'm not familiar enough with PyQt to give you the exact code, but you should be able to do something like this:

qindex_widget_child = std_item_child.index(QModelIndex())
self.setIndexWidget(qindex_widget_child, node_widget_child)

or like this:

qindex_widget_child = std_item.child(0, 1).index(QModelIndex())
self.setIndexWidget(qindex_widget_child, node_widget_child)
Phlucious
  • 3,704
  • 28
  • 61
  • Thanks, I eventually chose yours as the answer since I got inspired and came up with a workaround as I modified my question. Commenting to your ideas, neither one works unfortunately; the former adds widget on column 0. The method in the latter doesn't exist (pyqt mostly follows C++ api). – IsaacS Mar 08 '13 at 22:26
  • I looked into the code again and revised the second option into something hopefully more likely to work. I was a little sloppy with that one. Glad you were able to get something that works! – Phlucious Mar 08 '13 at 23:04
  • Your solution is more or less what I would do in c++, so I wouldn't really say it's sloppy. I'm a little hazy on whether you can invoke the child(0,1) function without assigning a child there first! – Phlucious Mar 08 '13 at 23:07