Search a QTableWidget and Select Matching Items

Finding and selecting matching items in a QTableWidget using findItems
Heads up! You've already completed this tutorial.

We've previously covered how to use search in a QTableView. However, if you're using QTableWidget instead of model views you may still want to be able to search through the items in the table and highlight or select them. In this tutorial we'll show you how to search a QTableWidget in Python and select matching items using the built-in findItems method.

Using findItems to Search a QTableWidget

The findItems method is the key to searching a QTableWidget. It scans through all cells in the table and returns items that match your search criteria. The method definition from the documentation is shown below (converted to Python).

python
[QTableWidgetItem] = QTableWidget.findItems(str, Qt.MatchFlags)

This tells us that the method accepts a str "text" to search, and a Qt.MatchFlags "flags" object which is what determines how we search. The .findItems method when called will return a list of QTableWidgetItem objects. These objects are the actual data items in the table. Once you have them, you can select a given item by calling .setCurrentItem and passing in an individual item, or for multiple-selection calling .setSelected(True) on the item itself.

Searching and Selecting a Single Item

Below is a complete working example showing a QTableWidget with a QLineEdit search box. As you type in the box, the first matching item is highlighted in the table view.

python

from PyQt5.QtWidgets import QTableWidget, QLineEdit, QPushButton, QApplication, QMainWindow, QVBoxLayout, QWidget, QTableWidgetItem
from PyQt5.QtCore import Qt

import random, string, sys


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()


        self.query = QLineEdit()
        self.query.setPlaceholderText("Search...")
        self.query.textChanged.connect(self.search)

        n_rows = 50
        n_cols = 4

        self.table = QTableWidget()
        self.table.setRowCount(n_rows)
        self.table.setColumnCount(n_cols)

        for c in range(0, n_cols):
            for r in range(0, n_rows):
                s = ''.join(random.choice(string.ascii_lowercase) for n in range(10))
                i = QTableWidgetItem(s)
                self.table.setItem(c, r, i)

        layout = QVBoxLayout()

        layout.addWidget(self.query)
        layout.addWidget(self.table)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

    def search(self, s):
        # Clear current selection.
        self.table.setCurrentItem(None)

        if not s:
            # Empty string, don't search.
            return

        matching_items = self.table.findItems(s, Qt.MatchContains)
        if matching_items:
            # We have found something.
            item = matching_items[0]  # Take the first.
            self.table.setCurrentItem(item)


app = QApplication(sys.argv)
w = MainWindow()
w.show()

app.exec_()
python

from PySide2.QtWidgets import QTableWidget, QLineEdit, QPushButton, QApplication, QMainWindow, QVBoxLayout, QWidget, QTableWidgetItem
from PySide2.QtCore import Qt

import random, string, sys


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()


        self.query = QLineEdit()
        self.query.setPlaceholderText("Search...")
        self.query.textChanged.connect(self.search)

        n_rows = 50
        n_cols = 4

        self.table = QTableWidget()
        self.table.setRowCount(n_rows)
        self.table.setColumnCount(n_cols)

        for c in range(0, n_cols):
            for r in range(0, n_rows):
                s = ''.join(random.choice(string.ascii_lowercase) for n in range(10))
                i = QTableWidgetItem(s)
                self.table.setItem(c, r, i)

        layout = QVBoxLayout()

        layout.addWidget(self.query)
        layout.addWidget(self.table)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

    def search(self, s):
        # clear current selection.
        self.table.setCurrentItem(None)

        if not s:
            # Empty string, don't search.
            return

        matching_items = self.table.findItems(s, Qt.MatchContains)
        if matching_items:
            # we have found something
            item = matching_items[0]  # take the first
            self.table.setCurrentItem(item)


app = QApplication(sys.argv)
w = MainWindow()
w.show()

app.exec_()

python

from PyQt6.QtWidgets import QTableWidget, QLineEdit, QPushButton, QApplication, QMainWindow, QVBoxLayout, QWidget, QTableWidgetItem
from PyQt6.QtCore import Qt

import random, string, sys


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()


        self.query = QLineEdit()
        self.query.setPlaceholderText("Search...")
        self.query.textChanged.connect(self.search)

        n_rows = 50
        n_cols = 4

        self.table = QTableWidget()
        self.table.setRowCount(n_rows)
        self.table.setColumnCount(n_cols)

        for c in range(0, n_cols):
            for r in range(0, n_rows):
                s = ''.join(random.choice(string.ascii_lowercase) for n in range(10))
                i = QTableWidgetItem(s)
                self.table.setItem(c, r, i)

        layout = QVBoxLayout()

        layout.addWidget(self.query)
        layout.addWidget(self.table)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

    def search(self, s):
        # clear current selection.
        self.table.setCurrentItem(None)

        if not s:
            # Empty string, don't search.
            return

        matching_items = self.table.findItems(s, Qt.MatchFlag.MatchContains)
        if matching_items:
            # we have found something
            item = matching_items[0]  # take the first
            self.table.setCurrentItem(item)


app = QApplication(sys.argv)
w = MainWindow()
w.show()

app.exec()
python

from PySide6.QtWidgets import QTableWidget, QLineEdit, QPushButton, QApplication, QMainWindow, QVBoxLayout, QWidget, QTableWidgetItem
from PySide6.QtCore import Qt

import random, string, sys


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()


        self.query = QLineEdit()
        self.query.setPlaceholderText("Search...")
        self.query.textChanged.connect(self.search)

        n_rows = 50
        n_cols = 4

        self.table = QTableWidget()
        self.table.setRowCount(n_rows)
        self.table.setColumnCount(n_cols)

        for c in range(0, n_cols):
            for r in range(0, n_rows):
                s = ''.join(random.choice(string.ascii_lowercase) for n in range(10))
                i = QTableWidgetItem(s)
                self.table.setItem(c, r, i)

        layout = QVBoxLayout()

        layout.addWidget(self.query)
        layout.addWidget(self.table)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

    def search(self, s):
        # clear current selection.
        self.table.setCurrentItem(None)

        if not s:
            # Empty string, don't search.
            return

        matching_items = self.table.findItems(s, Qt.MatchContains)
        if matching_items:
            # we have found something
            item = matching_items[0]  # take the first
            self.table.setCurrentItem(item)


app = QApplication(sys.argv)
w = MainWindow()
w.show()

app.exec_()

How the Search Method Works

The search method receives the textChanged signal from the QLineEdit as s. We first clear the current selection to simplify the conditions below: we don't need to clear on empty string and if there are no matches. Next we check if s is empty (not s is True if the string is empty). If it is we return without searching, leaving the table with no selection.

This step is necessary because calling .findItems with an empty string will return a list containing all currently selected items and None for non-selected items. This isn't what we want!

Once we know we have a search string we call .findItems with a Qt.MatchContains search, which will return any items containing the search string. If there are items, we take the first via matching_items[0] and set it as the current item (the currently selected item). If not, we clear the selection.

If you type a search string in the line input, you'll see the first matching item in the table selected (and highlighted) like below.

Searching a QTableWidget and selecting a single matching item in Python Search selecting a single item in the table

Selecting All Matching Items in a QTableWidget

If you would like to select all matching items in the table, you can iterate over the returned items and use .setSelected(True) on each one. This approach is useful when you want to highlight every cell that matches your search query. The modified search method is shown below.

python

class MainWindow(QMainWindow):

    # ... __init__ unchanged


    def search(self, s):
        # Clear current selection.
        self.table.setCurrentItem(None)

        if not s:
            # Empty string, don't search.
            return

        matching_items = self.table.findItems(s, Qt.MatchContains)
        if matching_items:
            # We have found something.
            for item in matching_items:
                item.setSelected(True)

This works similarly to the previous example. First we clear the active selection: here it is more important to do this, as we need to ensure previously selected items are unselected when the search string changes. As before we then check if s is empty, then perform the search. However, instead of setting only a single item we call setSelected on each item to mark it as selected. You'll see any matching items in the table highlighted as you type.

Searching a QTableWidget and selecting multiple matching items in Python Search selecting multiple items in the table

Below is a a short demo video.

You can experiment with different matching types for your QTableWidget search. Below are the available options in Qt.MatchFlags — for example starts with, contains, etc. and whether the search is case sensitive.

Flag Value Search type
Qt.MatchContains 1 The search term is contained in the item.
Qt.MatchStartsWith 2 The search term matches the start of the item.
Qt.MatchEndsWith 3 The search term matches the end of the item.
Qt.MatchWildcard 5 Performs string-based matching using a string with wildcards as the search term.
Qt.MatchFixedString 8 Performs string-based matching. String-based comparisons are case-insensitive unless the MatchCaseSensitive flag is also specified.
Qt.MatchRegularExpression 9 Performs string-based matching using a regular expression as the search term. Uses QRegularExpression. When using this flag, a QRegularExpression object can be passed as parameter and will directly be used to perform the search. The case sensitivity flag will be ignored as the QRegularExpression object is expected to be fully configured. This enum value was added in Qt 5.15.
Qt.MatchCaseSensitive 16 The search is case sensitive.

You can combine MatchCaseSensitive with other match flags to modify case matching behavior. For example Qt.MatchContains | Qt.MatchCaseSensitive would do a case-sensitive contains match.

For PyQt6 you must use the fully-qualified flag name, for example Qt.MatchFlag.MatchFixedString.

Summary

In this tutorial you learned how to search a QTableWidget in Python using the findItems method. You can find and select a single matching item using setCurrentItem, or highlight all matching items by iterating the results and calling setSelected(True) on each. The Qt.MatchFlags options give you control over whether to match by contains, starts with, ends with, wildcard, regular expression, or case sensitivity — making it easy to build flexible search functionality into your PyQt6, PyQt5, PySide6, or PySide2 table widgets.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

PyQt/PySide Development Services

Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.

Find out More

Martin Fitzpatrick

Search a QTableWidget and Select Matching Items was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.