codeBit
codeBit

Reputation: 94

Searching In QTableWidget

I've tried adding a search function on my QTableWidget on my own because the tutorials on google are either related to c++ or pyqt4. Now I know there's an easier way if I change it to QTableView so I'm down to change it if there's no other choice.

Here's my solution so far.

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.table = QTableWidget(self)
        self.search = QLineEdit(self)
        self.table.setColumnCount(2)

        self.table.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem('Name'))
        self.table.setHorizontalHeaderItem(1, QtWidgets.QTableWidgetItem('Age'))

        people = {'Bob': '43', 'Jeff': '22', 'Juan': '30'}
        self.table.setRowCount(len(people))
        for num, name in enumerate(people):
            name = QTableWidgetItem(name)
            age = QTableWidgetItem(people[name])
            
            self.table.setItem(num, 0, name)
            self.table.setItem(num, 1, age)
        
        self.search.textChanged.connect(self.findName)
    
    def findName(self):
        name_to_find = self.search.text()
        table_rows = self.table.rowCount()
        if table_rows != 0 and len(name) != 0:
            for row in range(self.table.rowCount()):
                if name_to_find not in self.table.item(row, 0).text():
                    self.table.hideRow(row)
        else:
            for row in range(table_rows):
                self.table.showRow(row)

There's two problems (that I know) in this.

  1. if name != self.table.item(row, 0).text() is too literal so I have to change it to: if name.lower() != self.table.item(row, 0).text().lower()

  2. (Important). Is that it doesn't detect backspace it does but when I backspace to a specific moment where multiple rows were shown I can't see them because the the function already hid them . So for example I write 'jeff' in the lineedit and backspaced until j. it doesn't show juan. I'd have to clear the lineedit first for everything to show up. A solution I thought of was adding a showRow function. (just thought of this as I'm writing and I'll try this as soon as I'm finished)

Anyways the main purpose of this post is to find a better way of searching a QTableWidget so I need the answer to this not my solution. But if you guys have a solution for mine you could also comment it so I can get a breath of relief.

An alternate idea of mine is highlighting the row (change the background color) but in the case of 100 poeple it'd be hard to fnd the highlight. a solution is to scroll to the item (.scrollToItem()) but if the user doesn't know the full name and knows only the 'J' part. where will it scroll to since there are multiple J's.

Upvotes: 2

Views: 3835

Answers (1)

musicamante
musicamante

Reputation: 48231

While hiding and showing rows can be fine for small data models, it requires some care and attention, otherwise it usually creates some logic issues just like yours. For future reference, consider using a QSortFilterProxyModel.

The problem is that you are just hiding the rows whenever the "search query" matches the items, but you don't restore other rows back if they were, since you only do that when the query is empty.

The solution is pretty simple: instead of showRow()/hideRow(), use setRowHidden, with the hide parameter based on the negative match:

    def findName(self):
        name = self.search.text().lower()
        for row in range(self.table.rowCount()):
            item = self.table.item(row, 0)
            # if the search is *not* in the item's text *do not hide* the row
            self.table.setRowHidden(row, name not in item.text().lower())

An unrelated note: always prefer layout managers; while yours is just a simple example, having UI elements overlapping like that is not a good thing (it's kind of disorienting and annoying, even for a basic code example: for instance, the window shows up very small, when it's resized the table keeps its small size, and the headers are not visible because they're hidden by the QLineEdit). Creating good questions also includes creating good results with the provided code: a simple QVBoxLayout would have sufficed and would have made your question even better.

Upvotes: 1

Related Questions