如何在Pyqt5 Python的QTableWidget中的列过滤器中添加搜索栏?

如何在Pyqt5 Python的QTableWidget中的列过滤器中添加搜索栏?,python,python-3.x,pyqt5,qtablewidget,qmenu,Python,Python 3.x,Pyqt5,Qtablewidget,Qmenu,我已经使用pyqt5创建了一个QTableWidget,并成功地在table widget的每一列中添加了filter选项,其中一个答案在stack overflow上可用。过滤器按预期工作,但我想在顶部的过滤器中添加搜索栏来搜索值 在我的实际脚本中,我可能在过滤器中有大约3-4k的唯一值,因此如果有一种方法可以在过滤器中搜索一个值,那么就很容易了 还有,有没有一种方法可以在这里添加滚动条,因为当前如果我向表中添加更多的值,我的筛选区域会越来越大,以累积所有值 我张贴最低限度的工作代码如下 U

我已经使用pyqt5创建了一个QTableWidget,并成功地在table widget的每一列中添加了filter选项,其中一个答案在stack overflow上可用。过滤器按预期工作,但我想在顶部的过滤器中添加搜索栏来搜索值

在我的实际脚本中,我可能在过滤器中有大约3-4k的唯一值,因此如果有一种方法可以在过滤器中搜索一个值,那么就很容易了

还有,有没有一种方法可以在这里添加滚动条,因为当前如果我向表中添加更多的值,我的筛选区域会越来越大,以累积所有值

我张贴最低限度的工作代码如下

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_())
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_())
我的脚本:

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_())
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_())

很好,您提供了一个MRE,但您忘记了最重要的事情:解释搜索栏所需的行为。当用户在搜索栏中键入时,它会从给定的唯一值中筛选选项。这就像在excel过滤器中有搜索栏,您可以在其中键入关键字并过滤可用的唯一值。1)不幸的是,我不使用excel,2)我知道在弹出窗口中必须显示唯一选项,以便选中它们。我说得对吗?3) 如果我在搜索栏中键入内容,那么是否应过滤表格或弹出窗口的选项?对于第2点,是。必须在弹出窗口中选中所有唯一选项。对于第3点,当我在搜索栏中键入时,它应该过滤弹出窗口的选项,并且我应该能够选中和取消选中过滤的选项。很好,您提供了MRE,但您忘记了最重要的事情:解释搜索栏所需的行为。当用户在搜索栏中键入时,它从给定的唯一值中筛选选项。这就像在excel过滤器中有搜索栏,您可以在其中键入关键字并过滤可用的唯一值。1)不幸的是,我不使用excel,2)我知道在弹出窗口中必须显示唯一选项,以便选中它们。我说得对吗?3) 如果我在搜索栏中键入内容,那么是否应过滤表格或弹出窗口的选项?对于第2点,是。必须在弹出窗口中选中所有唯一选项。对于第3点,当我在搜索栏中键入时,它应该过滤弹出窗口的选项,并且我应该能够选中和取消选中过滤的选项。