Search code examples
pythonpyqtpyqt5qlistwidget

Search/Filter custom Widgets for QListWidget


How can I search/filter custom widgets in the QListWidget?

For example, I have a custom form widget,

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

        self.ui = Ui_MetaInfo()
        self.ui.setupUi(self)
        self.data = data
        self.keywords = data['keywords']

        self.ui.pkg_name.setText(self.data['name'])
        self.ui.pkg_version.setText(self.data['version'])
        self.ui.pkg_desc.setText(self.data['desc'])
        self.ui.pkg_author_lbl.setText(self.data['author'])
        self.ui.pkg_pubdate_lbl.setText(self.data['pub_date'])

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

    def install_pkg(self):
        print('hello from {}'.format(self.data['name']))

I can add these to my MainWindow

class MainWindow(QtWidgets.QDialog):
    def __init__(self, data, parent=None):
        super(MainWindow, self).__init__(parent)
        self.data = data
        self.ui = Ui_Main()
        self.ui.setupUi(self)
        self.set_catalog_data()

    def set_catalog_data(self):
        for item in self.data:
            # print(item)
            metadata = MetadataForm(item)
            print(metadata.keywords)
            lst_item = QtWidgets.QListWidgetItem()
            self.ui.catalog_list_wid.insertItem(
                self.ui.catalog_list_wid.count(),
                lst_item
            )
            self.ui.catalog_list_wid.setItemWidget(lst_item, metadata)
            lst_item.setSizeHint(metadata.sizeHint())

In my MainWindow my UI has a QLineEdit, named self.ui.search_box, how can I filter my custom QListWidgetItem based the keywords attribute of my Metadata class?

Some simple testing data:

test_data = [
    {
        'name': 'Foo Model',
        'version': 'v1.0.0.1',
        'desc': lorem.paragraph(),
        'author': 'Jane Doe',
        'pub_date': '10/14/2018',
        'keywords': ['foo']
    },
    {
        'name': 'Bar Model',
        'version': 'v1.0.0.1',
        'desc': lorem.paragraph(),
        'author': 'Jon Smith',
        'pub_date': '11/2/2018',
        'keywords': ['bar']
    }
]

Solution

  • You just have to iterate over the rows and get keyword using the item () method to get the QListWidgetItem and then itemWidget to get the widget, using widget you get keywords and apply the filter, if you meet the filter it becomes visible otherwise you must hide

    class MainWindow(QtWidgets.QDialog):
        def __init__(self, data, parent=None):
            super(MainWindow, self).__init__(parent)
            self.data = data
            self.ui = Ui_Main()
            self.ui.setupUi(self)
            self.ui.search_box.textChanged.connect(self.on_textChanged)
            self.set_catalog_data()
    
        def set_catalog_data(self):
            for item in self.data:
                # print(item)
                metadata = MetadataForm(item)
                lst_item = QtWidgets.QListWidgetItem()
                self.ui.catalog_list_wid.insertItem(
                    self.ui.catalog_list_wid.count(),
                    lst_item
                )
                self.ui.catalog_list_wid.setItemWidget(lst_item, metadata)
                lst_item.setSizeHint(metadata.sizeHint())
    
        @QtCore.pyqtSlot(str)
        def on_textChanged(self, text):
            for row in range(self.ui.catalog_list_wid.count()):
                it = self.ui.catalog_list_wid.item(row)
                widget = self.ui.catalog_list_wid.itemWidget(it)
                if text: 
                    it.setHidden(not self.filter(text, widget.keywords))
                else:
                    it.setHidden(False)
    
        def filter(self, text, keywords):
            # foo filter
            # in the example the text must be in keywords
            return text in keywords