Search code examples
pythonpyqtpyqt5qlistwidgetqlistwidgetitem

PyQT: Get contents CustFormWidgetIem inside QListWidgetItem


I have a CustomFormWidgetItem that I add to a QListWidgetItem.

In the main widget, I am trying to query values on the CustomFormWidgetItem by

self.listWidget.currentItemChanged.connect(self.print_info)  # QListWidget

def print_info(self):
    print(self.listWidget.currentItem())
    print(self.listWidget.row(self.ui.catalog_list_wid.currentItem()))

When I click on a any item in the list I get,

<PyQt5.QtWidgets.QListWidgetItem object at 0x00000209A3831E58>
0  #  This is the row

I want the actual item inside the QListWidgetItem, how do I get that item?

EDIT (Add MVE):

class Roles:
    IdRole = QtCore.Qt.UserRole + 1000
    NameRole = QtCore.Qt.UserRole + 1001
    VersionRole = QtCore.Qt.UserRole + 1002
    InstalledRole = QtCore.Qt.UserRole + 1003

class ParentWid(QtWidgets.QDialog, Ui_ParentWidget):
    def __init__(self, data={}, parent=None):
        super(ParentWid, self).__init__(parent)
        self.data = data
        self.setupUi(self)
        self.set_widget_data()

    def set_widget_data(self):
        for item in self.data:
            lst_item = QtWidgets.QListWidgetItem()
            self.listWidget.addItem(lst_item)
            custFormItem = CustomFormWidget(item, lst_item)
            lst_item.setSizeHint(custFormItem.sizeHint())

    def print_results(self):
        v = (("id", Roles.IdRole), ("name", Roles.NameRole), ("version", Roles.VersionRole), ("installed", Roles.InstalledRole),)
        results = []
        for i in range(self.listWidget.count()):
            it = self.listWidget.item(i)
            d = {}
            for k, r in v:
                d[k] = it.data(r)
            results.append(d)
        print(results)

    # test
    def closeEvent(self, event):
        self.print_results()
        super(ParentWid, self).closeEvent(event)

class CustomFormWidget(QtWidgets.QWidget, Ui_Form):
    def __init__(self, data, item, parent=None):
        super(CustomFormWidget, self).__init__(parent)
        self._item = item
        self._item.listWidget().setItemWidget(self._item, self)
        self.setupUi(self)
        v = (("id", Roles.IdRole), ("name", Roles.NameRole), ("version", Roles.VersionRole), ("installed", Roles.InstalledRole),)
        for k, r in v:
            self._item.setData(r, data[k])
        self.update_view()
        self.install_btn.clicked.connect(self.on_click)

    def update_view(self):
        self.pkg_name.setText(self._item.data(Roles.NameRole))
        self.pkg_version.setText(self._item.data(Roles.VersionRole))
        v = self._item.data(Roles.InstalledRole)
        self.install_btn.setText("Installed" if v else "Not Installed")
        self.install_btn.setEnabled(not v)

    @QtCore.pyqtSlot()
    def on_click(self):
        self._item.setData(Roles.InstalledRole, not self._item.data(Roles.InstalledRole))
        self.update_view()

        v = (("id", Roles.IdRole), ("name", Roles.NameRole), ("version", Roles.VersionRole), ("installed", Roles.InstalledRole),)
        for k, r in v:
            print(k, self._item.data(r))


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)

    data = [
        {
            'id': 1,
            'name': 'pkg-foo',
            'version': '0.1',
            'installed': False
        },
        {
            'id': 2,
            'name': 'pkg-bar',
            'version': '0.1',
            'installed': False
        }
    ]
    w = ParentWid(data)
    w.show()
    sys.exit(app.exec_())

Solution

  • The currentItemChanged signal sends the current and the previous currentItem so we can use the first data directly. On the other hand, as the OP points out, its code is based on a previous answer from me in which it states that in these cases it is better to save the data in the QListWidget since it has an internal model, so in this case we can take advantage of this to obtain the data:

    class ParentWid(QtWidgets.QDialog, Ui_ParentWidget):
        def __init__(self, data={}, parent=None):
            super(ParentWid, self).__init__(parent)
            self.data = data
            self.setupUi(self)
            self.set_widget_data()
            self.listWidget.currentItemChanged.connect(self.print_info)
    
        @QtCore.pyqtSlot("QListWidgetItem *", "QListWidgetItem *")
        def print_info(self, current, previous):
            print("="*20)
            v = (("id", Roles.IdRole), ("name", Roles.NameRole), ("version", Roles.VersionRole), ("installed", Roles.InstalledRole),)
            for k, r in v:
                print(k,  current.data(r))
    
        def set_widget_data(self):
            for item in self.data:
                lst_item = QtWidgets.QListWidgetItem()
                self.listWidget.addItem(lst_item)
                custFormItem = CustomFormWidget(item, lst_item)
                lst_item.setSizeHint(custFormItem.sizeHint())