如何检测QTableWidget列头点击并实现Pandas数据排序?
QTableWidget列头点击排序实现问题
我查看了QTableWidget的cellClicked文档,目前能实现表格单元格的点击响应,但无法触发列头的点击信号。希望点击列头时用Pandas对数据进行升序排序并更新表格,且未找到获取列头单元格的相关调用。参考相关问题示例后,我更新了代码,计划根据自身需求修改。
import pandas as pd from PySide6 import QtCore, QtWidgets from PySide6.QtCore import Qt class PandasTableModel(QtCore.QAbstractTableModel): def __init__(self, parent=None, *args): super(PandasTableModel, self).__init__(parent, *args) self._filters = {} self._sortBy = [] self._sortDirection = [] self._dfSource = pd.DataFrame() self._dfDisplay = pd.DataFrame() def rowCount(self, parent=QtCore.QModelIndex()): if parent.isValid(): return 0 return self._dfDisplay.shape[0] def columnCount(self, parent=QtCore.QModelIndex()): if parent.isValid(): return 0 return self._dfDisplay.shape[1] def data(self, index, role): if index.isValid() and role == QtCore.Qt.ItemDataRole.DisplayRole: return self._dfDisplay.values[index.row()][index.column()] return None def headerData(self, col, orientation=QtCore.Qt.Orientation.Horizontal, role=QtCore.Qt.ItemDataRole.DisplayRole): if orientation == QtCore.Qt.Orientation.Horizontal and role == QtCore.Qt.ItemDataRole.DisplayRole: return str(self._dfDisplay.columns[col]) return None def setupModel(self, header, data): self._dfSource = pd.DataFrame(data, columns=header) self._sortBy = [] self._sortDirection = [] self.setFilters({}) def setFilters(self, filters): self.modelAboutToBeReset.emit() self._filters = filters self.updateDisplay() self.modelReset.emit() def updateDisplay(self): dfDisplay = self._dfSource.copy() # Filtering cond = pd.Series(True, index = dfDisplay.index) for column, value in self._filters.items(): cond = cond & \ (dfDisplay[column].str.lower().str.find(str(value).lower()) >= 0) dfDisplay = dfDisplay[cond] # Sorting if len(self._sortBy) != 0: dfDisplay.sort_values(by=self._sortBy, ascending=self._sortDirection, inplace=True) # Updating self._dfDisplay = dfDisplay def sort(self, col, order=QtCore.Qt.SortOrder.AscendingOrder): # Storing persistent indexes self.layoutAboutToBeChanged.emit() oldIndexList = self.persistentIndexList() oldIds = self._dfDisplay.index.copy() # Sorting data column = self._dfDisplay.columns[col] ascending = (order == QtCore.Qt.SortOrder.AscendingOrder) if column in self._sortBy: i = self._sortBy.index(column) self._sortBy.pop(i) self._sortDirection.pop(i) self._sortBy.insert(0, column) self._sortDirection.insert(0, ascending) self.updateDisplay() # Updating persistent indexes newIds = self._dfDisplay.index newIndexList = [] for index in oldIndexList: id = oldIds[index.row()] newRow = newIds.get_loc(id) newIndexList.append(self.index(newRow, index.column(), index.parent())) self.changePersistentIndexList(oldIndexList, newIndexList) self.layoutChanged.emit() self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex()) class Ui_TableFilteringDialog(object): def setupUi(self, TableFilteringDialog): TableFilteringDialog.setObjectName("TableFilteringDialog") TableFilteringDialog.resize(400, 300) self.verticalLayout = QtWidgets.QVBoxLayout(TableFilteringDialog) self.verticalLayout.setObjectName("verticalLayout") self.tableView = QtWidgets.QTableView(TableFilteringDialog) self.tableView.setObjectName("tableView") self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.verticalLayout.addWidget(self.tableView) self.groupBox = QtWidgets.QGroupBox(TableFilteringDialog) self.groupBox.setObjectName("groupBox") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox) self.verticalLayout_2.setObjectName("verticalLayout_2") self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") self.column1Label = QtWidgets.QLabel(self.groupBox) self.column1Label.setObjectName("column1Label") self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.column1Label) self.column1Field = QtWidgets.QLineEdit(self.groupBox) self.column1Field.setObjectName("column1Field") self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.column1Field) self.column2Label = QtWidgets.QLabel(self.groupBox) self.column2Label.setObjectName("column2Label") self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.column2Label) self.column2Field = QtWidgets.QLineEdit(self.groupBox) self.column2Field.setObjectName("column2Field") self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.column2Field) self.verticalLayout_2.addLayout(self.formLayout) self.verticalLayout.addWidget(self.groupBox) self.retranslateUi(TableFilteringDialog) QtCore.QMetaObject.connectSlotsByName(TableFilteringDialog) def retranslateUi(self, TableFilteringDialog): _translate = QtCore.QCoreApplication.translate TableFilteringDialog.setWindowTitle(_translate("TableFilteringDialog", "Dialog")) self.groupBox.setTitle(_translate("TableFilteringDialog", "Filters")) self.column1Label.setText(_translate("TableFilteringDialog", "Name")) self.column2Label.setText(_translate("TableFilteringDialog", "Occupation")) class TableFilteringDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(TableFilteringDialog, self).__init__(parent) self.ui = Ui_TableFilteringDialog() self.ui.setupUi(self) self.tableModel = PandasTableModel() header = ['Name', 'Occupation'] data = [ ['Abe', 'President'], ['Angela', 'Chancelor'], ['Donald', 'President'], ['François', 'President'], ['Jinping', 'President'], ['Justin', 'Prime minister'], ['Theresa', 'Prime minister'], ['Vladimir', 'President'], ['Donald', 'Duck'] ] self.tableModel.setupModel(header, data) self.ui.tableView.setModel(self.tableModel) self.ui.column1Field.textEdited.connect(self.filtersEdited) self.ui.column2Field.textEdited.connect(self.filtersEdited) def filtersEdited(self): filters = {} values = [ self.ui.column1Field.text().lower(), self.ui.column2Field.text().lower() ] for col, value in enumerate(values): if value == '': continue column = self.tableModel.headerData(col, QtCore.Qt.Orientation.Horizontal, QtCore.Qt.ItemDataRole.DisplayRole).value() filters[column]=value self.tableModel.setFilters(filters) if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) dialog = TableFilteringDialog() dialog.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者David Frick
相关产品推荐
相关产品推荐

