1

I have a created a QTableWidget using pyqt5 and managed to add filter option in each column of the table widget successfully with one of the answers available on stack overflow. filters works as expected but I wanted to add search bar in the filter at the top to search for the values.

In my actual Script I would probably have around 3-4k unique values in filter so it becomes easy if there's a way to search for a value in the filter.

Also, Is there a way we can add scroll bar in this because currently if I add more values to the table, my filter area gets bigger and bigger to accumulate all values.

enter image description here

I am posting minimal working code below.

Code Generated by UIDesigner:

from PyQt5 import QtCore, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(10, 10, 771, 561))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

My Script:

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QTableWidgetItem
import pandas as pd

from demo import Ui_MainWindow

class DemoTable(QtWidgets.QMainWindow, Ui_MainWindow):  
    #signalrunningriskmanagertext = QtCore.pyqtSignal(str)

    def __init__(self):
        super(DemoTable, self).__init__()
        self.setupUi(self) 

        #Set up table data
        self.tableWidget.setRowCount(25)
        self.tableWidget.setColumnCount(4)

        self.tableWidget.setHorizontalHeaderLabels(['A','B','C','D'])
        d = {'A': range(0,25), 
             'B': range(20,45),
             'C': ['a','b','c','d','e','f','g','h','i','d','s','n','s','t','h','d','t','s','t','s','e','y','d','b','s'],
             'D': ['a','b','c','d','e','f','g','h','i','d','s','n','s','t','h','d','t','s','t','s','e','y','d','b','s']}
        df = pd.DataFrame(data=d)

        for row in range(0,25):
            for column in range(0,4):
                item = QTableWidgetItem(str(df.iloc[row,column]))
                self.tableWidget.setItem(row, column, item)

        #Add filters in column
        self.tableWidgetHeader = self.tableWidget.horizontalHeader()
        self.tableWidgetHeader.sectionClicked.connect(self.columnfilterclicked)
        self.keywords = dict([(i, []) for i in range(self.tableWidget.columnCount())])
        self.checkBoxs = []
        self.col = None

    def slotSelect(self, state):
        for checkbox in self.checkBoxs:
            checkbox.setChecked(QtCore.Qt.Checked == state)

    def menuClose(self):
        self.keywords[self.col] = []
        for element in self.checkBoxs:
            if element.isChecked():
                self.keywords[self.col].append(element.text())
        self.filterdata()
        self.menu.close()

    def clearFilter(self):
        if self.tableWidget.rowCount() > 0:
            for i in range(self.tableWidget.rowCount()):
                self.tableWidget.setRowHidden(i, False)

    def filterdata(self):
        columnsShow = dict([(i, True) for i in range(self.tableWidget.rowCount())])

        for i in range(self.tableWidget.rowCount()):
            for j in range(self.tableWidget.columnCount()):
                item = self.tableWidget.item(i, j)
                if self.keywords[j]:
                    if item.text() not in self.keywords[j]:
                        columnsShow[i] = False
        for key in columnsShow:
            self.tableWidget.setRowHidden(key, not columnsShow[key])

    def columnfilterclicked(self,index):
        self.menu = QtWidgets.QMenu(self)
        self.col = index

        data_unique = []

        self.checkBoxs = []

        checkBox = QtWidgets.QCheckBox("Select all", self.menu)
        checkableAction = QtWidgets.QWidgetAction(self.menu)
        checkableAction.setDefaultWidget(checkBox)
        self.menu.addAction(checkableAction)
        checkBox.setChecked(True)
        checkBox.stateChanged.connect(self.slotSelect)

        for i in range(self.tableWidget.rowCount()):
            if not self.tableWidget.isRowHidden(i):
                item = self.tableWidget.item(i, index)
                if item.text() not in data_unique:
                    data_unique.append(item.text())
                    checkBox = QtWidgets.QCheckBox(item.text(), self.menu)
                    checkBox.setChecked(True)
                    checkableAction = QtWidgets.QWidgetAction(self.menu)
                    checkableAction.setDefaultWidget(checkBox)
                    self.menu.addAction(checkableAction)
                    self.checkBoxs.append(checkBox)

        btn = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
                                     QtCore.Qt.Horizontal, self.menu)
        btn.accepted.connect(self.menuClose)
        btn.rejected.connect(self.menu.close)
        checkableAction = QtWidgets.QWidgetAction(self.menu)
        checkableAction.setDefaultWidget(btn)
        self.menu.addAction(checkableAction)

        headerPos = self.tableWidget.mapToGlobal(self.tableWidgetHeader.pos())

        posY = headerPos.y() + self.tableWidgetHeader.height()
        posX = headerPos.x() + self.tableWidgetHeader.sectionPosition(index)
        self.menu.exec_(QtCore.QPoint(posX, posY))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = DemoTable()
    window.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
PyPyVk
  • 79
  • 4
  • 14
  • 1
    It is great that you have provided an MRE but you have forgotten the most important thing: Explain the desired behavior of the search bar. – eyllanesc May 27 '20 at 14:29
  • 1
    when user type in searchbar, it filters option from the given unique values. it is like having search bar in excel filters where you can type keyword and filter available unique values. – PyPyVk May 27 '20 at 14:34
  • 1) I don't use excel unfortunately, 2) I understand that in the popup the unique options must appear so that they are checked. Am I correct? 3) If I type something in the search bar then should the table or the options of the popup be filtered? – eyllanesc May 27 '20 at 15:06
  • for point 2 yes. all unique options must be checked in pop up. for point 3, it should filter options of the popup when i type in search bar, and i should be able to check and uncheck the filtered options. – PyPyVk May 27 '20 at 15:09

0 Answers0