2

I am trying to subclass a QListWidget and add a searchbox above it. I know I could create this by subclassing a QWidget and giving it a layout containing both a QListWidget and QLineEdit, but I'd rather it be a direct subclass of QListWidget so it can easily replace existing QListWidgets in my code and retain all the inherited methods that may be called by the parent widgets.

This is my attempt, but I'm not sure how to put the QListWidget inside a layout along with the QLineEdit, layout.addWidget(self) didn't work.

import re
from PyQt5 import QtCore, QtGui, QtWidgets


class SearchableListWidget(QtWidgets.QListWidget):
    def __init__(self, items, parent=None):
        super().__init__(parent=parent)

        self.initial_items = items
        self.set_items(items)

        self.search_box = QtWidgets.QLineEdit()
        self.search_box.textChanged.connect(self.filter)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.search_box)
        self.setLayout(layout)

    def filter(self):
        filtered_items = [item for item in self.initial_items
                          if re.search(self.search_box.text().lower(), item.lower())]

        self.set_items(filtered_items)

    def get_items(self):
        return [str(self.item(i).text()) for i in range(self.count())]

    def set_items(self, items):
        self.clear()
        for name in items:
            self.addItem(name)


if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)

    test = SearchableListWidget(['a', 'b', 'c'])
    test.show()

    sys.exit(app.exec_())

What I get:
enter image description here

What I want:
enter image description here

1 Answer 1

1

The problem is the structure of your program: The window is SearchableListWidget which is a QListWidget where you placed a QLineEdit through a layout, but the correct thing to do is create a class that inherits from a container like QWidget and there place the QLineEdit and the QListWidget vertically through a QVBoxLayout:

import re
from PyQt5 import QtCore, QtGui, QtWidgets


class SearchableWidget(QtWidgets.QWidget):
    def __init__(self, items, parent=None):
        super().__init__(parent)

        self.search_box = QtWidgets.QLineEdit()
        self.search_box.textChanged.connect(self.filter)

        self.list_widget = QtWidgets.QListWidget()

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.search_box)
        layout.addWidget(self.list_widget)

        self.initial_items = items
        self.set_items(items)

    def filter(self):
        filtered_items = [
            item
            for item in self.initial_items
            if re.search(self.search_box.text().lower(), item.lower())
        ]

        self.set_items(filtered_items)

    def get_items(self):
        return [
            str(self.list_widget.item(i).text())
            for i in range(self.list_widget.count())
        ]

    def set_items(self, items):
        self.list_widget.clear()
        for name in items:
            self.list_widget.addItem(name)


if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)

    test = SearchableWidget(["a", "b", "c"])
    test.show()

    sys.exit(app.exec_())
Sign up to request clarification or add additional context in comments.

1 Comment

I think the OP was looking for a way to do it as a direct subclass of QListWidget so it can be a replacement for other list widgets, i.e. without having to reimplement the functions of a QListWidget. I'm asking because I'm trying to do the same thing

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.