spitfiredd
spitfiredd

Reputation: 3135

Pyqt5 refresh/update QListWidget based on event in custom widget?

I am trying to update/refresh a QListWidget after I click a button in a CustomFormWidget.

What I am trying to do is when I click the button in a CustomFormWidget, it updates the class variable data in the ParentWid and then rebuilds/updated/refreshes ParentWid.ui.listWidget. Where and how should I add this logic. Should I add to my CustomFormWidget.on_click method or should my logic be set in the ParentWid?

So far my code looks like:

from PyQt5 import QtCore, QtGui, QtWidgets


class ParentWid(QtWidgets.QDialog):
    data = [
        {
            'id': 1,
            'name': 'pkg-foo',
            'version': '0.1',
            'installed': False
        },
        {
            'id': 2,
            'name': 'pkg-bar',
            'version': '0.1',
            'installed': False
        }
    ]

    def __init__(self, parent=None):
        super(ParentWid, self).__init__(parent)
        self.ui = Ui_ParentWidget()
        self.ui.setupUi(self)
        self.set_widget_data()

    @classmethod
    def update_installed_packages(cls, value):
        for item in ParentWid.data:
            if item["id"] == value:
                item["installed"] = not item["installed"]

    def set_widget_data(self):
        for item in ParentWid.data:
            custFormItem = CustomFormWidget(item)
            lst_item = QtWidgets.QListWidgetItem()
            self.ui.listWidget.insertItem(
                self.ui.listWidget.count(),
                lst_item
            )
            self.ui.listWidget.setItemWidget(lst_item, custFormItem)
            lst_item.setSizeHint(custFormItem.sizeHint())



class CustomFormWidget(QtWidgets.QWidget):
    def __init__(self, data, parent=None):
        super(CustomFormWidget, self).__init__(parent)

        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.data = data

        self.ui.pkg_name.setText(self.data['name'])
        self.ui.pkg_version.setText(self.data['version'])

        if self.data["installed"] is True:
            self.ui.install_btn.setText("Installed")
            self.ui.install_btn.setEnabled(False)

        self.ui.install_btn.clicked.connect(self.on_click)

    def on_click(self):
        print('installed pkg')
        ## install LOGIG
        ParentWid.update_installed_packages(self.data["id"])

Upvotes: 1

Views: 1984

Answers (1)

eyllanesc
eyllanesc

Reputation: 244301

In this case it is better that each item manages its data, for this we can pass the QListWidget to the custom widget and in it handle through roles. In the following example, each widget modifies its data, and when the application is closed, the updated data is printed:

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_())

Upvotes: 1

Related Questions