Python Forum
[PyQt] [Solved]Display Search Results in QTable
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] [Solved]Display Search Results in QTable
#3
You can also use QTreeview with column filters.

import sys
import re
from PyQt5 import QtWidgets, QtGui, QtCore, QtSql

TRACE = True

MY_TABLE = "items"
db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("inventory.db")

modelQuery = QtSql.QSqlQueryModel()
modelTable = QtSql.QSqlRelationalTableModel()

g_hits_count = 0
g_total_count = 0
g_selected_count = 0


def trace(message):
    if TRACE:
        print(message)


def _human_key(key):
    parts = re.split(r"(\d*\.\d+|\d+)", key)
    return tuple(
        (e.swapcase() if i % 2 == 0 else float(e)) for i, e in enumerate(parts)
    )


class FilterHeader(QtWidgets.QHeaderView):
    filterActivated = QtCore.pyqtSignal()

    def __init__(self, parent):
        super().__init__(QtCore.Qt.Horizontal, parent)
        self._editors = []
        self._padding = 4
        self.setStretchLastSection(True)
        self.setDefaultAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
        self.setSortIndicatorShown(False)
        self.sectionResized.connect(self.adjustPositions)
        parent.horizontalScrollBar().valueChanged.connect(self.adjustPositions)

    def setFilterBoxes(self, count):
        while self._editors:
            editor = self._editors.pop()
            editor.deleteLater()
        for index in range(count):
            editor = QtWidgets.QLineEdit(self.parent())
            editor.setPlaceholderText("Filter")
            editor.setClearButtonEnabled(True)
            editor.textChanged.connect(self.textChanged)

            self._editors.append(editor)
        self.adjustPositions()

    def textChanged(self):
        self.filterActivated.emit()

    def sizeHint(self):
        size = super().sizeHint()
        if self._editors:
            height = self._editors[0].sizeHint().height()
            size.setHeight(size.height() + height + self._padding)
        return size

    def updateGeometries(self):
        if self._editors:
            height = self._editors[0].sizeHint().height()
            self.setViewportMargins(0, 0, 0, height + self._padding)
        else:
            self.setViewportMargins(0, 0, 0, 0)
        super().updateGeometries()
        self.adjustPositions()

    def adjustPositions(self):
        for index, editor in enumerate(self._editors):
            height = editor.sizeHint().height()
            editor.move(
                self.sectionPosition(index) - self.offset() + 2,
                height + (self._padding // 2),
            )
            editor.resize(self.sectionSize(index), height)

    def filterText(self, index):
        if 0 <= index < len(self._editors):
            return self._editors[index].text()
        return ""

    def setFilterText(self, index, text):
        if 0 <= index < len(self._editors):
            self._editors[index].setText(text)

    def clearFilters(self):
        for editor in self._editors:
            editor.clear()


class HumanProxyModel(QtCore.QSortFilterProxyModel):
    def lessThan(self, source_left, source_right):
        data_left = source_left.data()
        data_right = source_right.data()
        return True
        if type(data_left) == type(data_right) == str:
            return _human_key(data_left) < _human_key(data_right)
        return super(HumanProxyModel, self).lessThan(source_left, source_right)

    @property
    def filters(self):
        if not hasattr(self, "_filters"):
            self._filters = []
        return self._filters

    @filters.setter
    def filters(self, filters):
        self._filters = filters
        self.invalidateFilter()

        global g_hits_count
        g_hits_count = self.rowCount()

    def filterAcceptsRow(self, sourceRow, sourceParent):
        for i, text in self.filters:
            if 0 <= i < self.sourceModel().columnCount():
                ix = self.sourceModel().index(sourceRow, i, sourceParent)
                data = ix.data()
                if text not in data.lower():
                    return False

        return True


class winMain(QtWidgets.QMainWindow):
    cur_row = -1
    row_id = -1

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Music List")
        self.setupUi()
        self.setGeometry(0, 0, 900, 800)

        self.show()

    def closeEvent(self, event):
        self.deleteLater()


    def handleFilterActivated(self):
        header = self.treeView.header()
        filters = []
        for i in range(header.count()):
            text = header.filterText(i)
            if text:
                filters.append((i, text))
        proxy = self.treeView.model()
        proxy.filters = filters

        self.updateStatus()
        self.treeView.setCurrentIndex(self.treeView.model().index(0, 0))


    def keyReleaseEvent(self, eventQKeyEvent):
        key = eventQKeyEvent.key()
        modifiers = QtWidgets.QApplication.keyboardModifiers()
        if modifiers == QtCore.Qt.ShiftModifier and key == QtCore.Qt.Key_Escape:
            self.clear_all_filters()

    def keyPressEvent(self, event):
        key = event.key()

        modifiers = QtWidgets.QApplication.keyboardModifiers()

        if modifiers != QtCore.Qt.ShiftModifier:
            focus_obj = self.focusWidget()

            if key == QtCore.Qt.Key_Return:
                if isinstance(focus_obj, QtWidgets.QTreeView):
                    self.edit_record(self.treeView.currentIndex())

            elif key == QtCore.Qt.Key_Escape:
                if isinstance(focus_obj, QtWidgets.QLineEdit):
                    focus_obj.clear()

    def clear_all_filters(self):
        # clear all inputs of type QLineEdit
        lineEdits = self.findChildren(QtWidgets.QLineEdit)
        for lineEdit in lineEdits:
            lineEdit.clear()
        
    def setupUi(self):
        self.setWindowIcon(QtGui.QIcon.fromTheme("applications-multimedia"))
        self.centralwidget = QtWidgets.QWidget(self)
        hBox = QtWidgets.QHBoxLayout(self.centralwidget)
        
        self.treeView = QtWidgets.QTreeView(self.centralwidget)
        self.treeView.setSelectionBehavior(1)
        self.treeView.setRootIsDecorated(False)
        self.treeView.setSortingEnabled(True)
        self.treeView.setAlternatingRowColors(True)
        self.treeView.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked)
        self.treeView.setSelectionMode(1)
        self.treeView.header().setStretchLastSection(True)

        hBox.addWidget(self.treeView)
        self.setCentralWidget(self.centralwidget)

        header = FilterHeader(self.treeView)
        self.treeView.setHeader(header)

        # StatusBar
        self.statusBar = self.statusBar()
        self.setStatusBar(self.statusBar)
        
        modelTable.setTable(MY_TABLE)

        modelTable.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)

        self.treeView.setModel(modelTable)
        while modelTable.canFetchMore():
            modelTable.fetchMore()
        if not TRACE:
            self.treeView.setColumnHidden(0, True)

        # enable human sorting
        proxy = HumanProxyModel(self)
        
        proxy.setSourceModel(modelTable)
        self.treeView.setModel(proxy)

        # enable filtering
        header.setFilterBoxes(modelTable.columnCount())
        header.filterActivated.connect(self.handleFilterActivated)

        # update counters
        global g_total_count, g_hits_count
        g_total_count = modelTable.rowCount()
        g_hits_count = g_total_count
        self.treeView.setColumnWidth(0, 200)
        self.treeView.setColumnWidth(1, 300)
        self.treeView.hideColumn(3)
        
        self.setWindowTitle(f"Inventory - {str(g_total_count)} Items")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = winMain()
    sys.exit(app.exec_())
Reply


Messages In This Thread
[Solved]Display Search Results in QTable - by Extra - Jun-02-2022, 06:00 PM
RE: Display Search Results in QTable - by Axel_Erfurt - Jun-02-2022, 07:07 PM
RE: Display Search Results in QTable - by Extra - Jun-02-2022, 07:36 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Search data in treeview without search button TomasSanchexx 3 1,729 Aug-12-2023, 03:17 AM
Last Post: deanhystad
  [PyQt] [solved] How to display a pdf-file in a PyQt6 widget BigMan 13 16,632 May-06-2023, 09:27 AM
Last Post: Axel_Erfurt
  [PyQt] [Solved]Display PyQtTable results from A->Z & Z->A Extra 2 1,208 Jul-18-2022, 04:04 PM
Last Post: Extra
  [PyQt] [Solved]Help Adding Sql Results in ComboBox Extra 2 1,290 Jul-07-2022, 09:46 PM
Last Post: Extra
  [PyQt] [Solved]Help Adding results from for loop Extra 2 1,500 Jun-24-2022, 05:01 PM
Last Post: Extra
  How to display results from terminal window onto tkinter. buttercup 0 3,693 Jul-21-2020, 04:41 AM
Last Post: buttercup
  [Tkinter] add search bar = search for input in all computer directory francisco_neves2020 15 11,081 Apr-14-2019, 07:29 PM
Last Post: francisco_neves2020
  Display and update the label text which display the serial value jenkins43 5 9,183 Feb-04-2019, 04:36 AM
Last Post: Larz60+
  Display more than one button in GUI to display MPU6000 Sensor readings barry76 4 3,999 Jan-05-2019, 01:48 PM
Last Post: wuf
  [PyQt] I am unable to connect Qtable widget in another tab? aditech 1 2,509 Sep-13-2018, 04:44 PM
Last Post: Axel_Erfurt

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020