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 quick tutorial we'll show how to do that.
Searching in a QTableWidget
is handled with the .findItems
method. The method definition from the documentation is shown below (converted to 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.
Below is a quick example showing a QTableWidget
with a QLineEdit
search box. As you type in the box matching items are highlighted in the table view.
- PyQt5
- PySide2
- PyQt6
- PySide6
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_()
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_()
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()
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_()
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.
Never miss an update
Enjoyed this? Subscribe to get new updates straight in your Inbox.
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.
Search selecting a single item in the table
If you would like to select all matching items in the table, you can iterate the items and use .setSelected(True)
instead. The modified
search
method is shown below.
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 selected items are unselected when the search string is extended. 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.
Search selecting multiple items in the table
Below is a a short demo video.
You can experiment with different matching types for your 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 searches 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
.