Search code examples
pythonpython-2.7user-interfacepyqt4model-view

PyQt4 QAbstractListModel - Only first data widget is displayed


I'm trying to implement the QAbstractListModel class in order to display several similar widgets. The following code shows my problem:

import sys
from PyQt4 import QtCore
from PyQt4 import QtGui

class Model(QtCore.QAbstractListModel):

    def __init__(self, parent=None):
        super(QtCore.QAbstractListModel, self).__init__(parent)
        self._widgets = []


    def headerData(self, section, orientation, role):
        """ Returns header for columns """
        return "bla"


    def rowCount(self, parentIndex=QtCore.QModelIndex()):
        """ Returns number of interfaces """
        return len(self._widgets)


    def data(self, index, role):
        """ Returns the data to be displayed """
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            return self._widgets[row]


    def insertRow(self, widget, parentIndex=QtCore.QModelIndex()):
        """ Inserts a row into the model """
        self.beginInsertRows(parentIndex, 0, 1)
        self._widgets.append(widget)
        self.endInsertRows()


class Widget(QtGui.QWidget):

    def __init__(self, parent=None, name="None"):
        super(QtGui.QWidget, self).__init__(parent)
        self.layout = QtGui.QHBoxLayout()
        self.setLayout(self.layout)
        self.checkbox = QtGui.QCheckBox()
        self.button = QtGui.QPushButton(self)
        self.label = QtGui.QLabel(self)
        self.label.setText(name)
        self.layout.addWidget(self.checkbox)
        self.layout.addWidget(self.button)
        self.layout.addWidget(self.label)

class Window(QtGui.QMainWindow):

    def __init__(self, parent=None):
        super(QtGui.QMainWindow, self).__init__(parent)
        self.view = QtGui.QListView(self)
        self.model = Model()
        self.view.setModel(self.model)
        self.setCentralWidget(self.view)

        self.model.insertRow(
            widget=Widget(self)
        )
        self.model.insertRow(
            widget=Widget(self)
        )
        self.model.insertRow(
            widget=Widget(self)
        )
        self.model.insertRow(
            widget=Widget(self)
        )

        self.show()


app = QtGui.QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())

It works, there are four clickable entries in the list, but in only one of them the widget is actually displayed. Why is that?

I guess this behaviour is either caused by data() or how I'm using beginInsertRows(), but I can't figure out where the error is.


ìnsertRow() function now looks like that

def insertRow(self, widget, parentIndex=QtCore.QModelIndex()):
    """ Inserts a row into the model """
    self.beginInsertRows(parentIndex, len(self._widgets), len(self._widgets))
    self._widgets.append(widget)
    self.endInsertRows()

but it still does not work.


Solution

  • Actually, the four widgets are displayed. The issue is, they're all displayed in the top left corner. You can see they overlap if you put names, here "1", "2", "3", "4":

    enter image description here

    Fixing the row numbers doesn't solve the issue. The widgets will be in the correct rows but will still be displayed on the top left. It is because data is supposed to return text for the display role.

    To display simple widgets, I suggest using QListWidget and the setItemWidget method. Otherwise you'll have to use delegates.