QTableView搭配QSortFilterProxyModel排序后无法正确定位并选中目标行的技术求助
解决QSortFilterProxyModel排序后QTableView选中行失效的问题
嗨,我完全明白你遇到的问题了——当代理模型排序后,源模型的行号和表格展示的行号已经对不上了,而且你还搞反了索引转换的方法,这才导致了那个报错。下面给你具体的解决思路和修改后的代码:
问题出在哪?
- 你在源模型(QStandardItemModel)上调用
match得到的索引,属于源模型本身,但mapToSource是用来把代理模型的索引转换成源模型索引的,反过来转换应该用mapFromSource。 - 当代理模型执行排序后,它的行顺序和源模型完全不一样了,直接用源模型的行号去调用
selectRow,自然找不到正确的行。
两种可行的解决方案
方案1:转换源模型索引到代理模型
修改你的find_text方法,把源模型的匹配索引转换成代理模型对应的索引,再选中行:
def find_text(self, text): column = 0 self.table_view.clearSelection() start = self.table_model.index(0, column) matches = self.table_model.match(start, Qt.DisplayRole, text, hits=1, flags=Qt.MatchContains) if matches: # 获取源模型里的匹配索引 source_index = matches[0] # 把源模型索引转成代理模型的索引(这才是表格实际展示的索引) proxy_index = self.model_filter_proxy.mapFromSource(source_index) # 用代理模型的行号选中行 self.table_view.selectRow(proxy_index.row())
方案2:直接在代理模型上执行匹配(更简洁)
其实完全可以跳过源模型,直接在代理模型上调用match方法,这样得到的就是和表格展示对应的索引,不需要转换:
def find_text(self, text): column = 0 self.table_view.clearSelection() # 直接从代理模型的起始索引开始匹配 start = self.model_filter_proxy.index(0, column) matches = self.model_filter_proxy.match(start, Qt.DisplayRole, text, hits=1, flags=Qt.MatchContains) if matches: # 直接用匹配到的代理模型行号选中 self.table_view.selectRow(matches[0].row())
完整修改后的代码
我把两种方案都注释在代码里了,你可以按需选择:
from PyQt5.QtWidgets import (QApplication, QPushButton,QComboBox,QMainWindow) from PyQt5.QtWidgets import (QTableView,QAbstractItemView,QVBoxLayout,QLineEdit,QWidget) from PyQt5.QtGui import QStandardItemModel,QStandardItem from PyQt5.QtCore import QSortFilterProxyModel,Qt class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setup_gui() def setup_gui(self): widget=QWidget(self) self.setCentralWidget(widget) self.qlineedit = QLineEdit() self.qlineedit.textChanged.connect(self.find_text) self.table_view = QTableView() self.main_layout = QVBoxLayout(widget) self.main_layout.addWidget(self.qlineedit) self.main_layout.addWidget(self.table_view) self.table_model = QStandardItemModel() row=0 for b in ['Fast','Medium','Cool','Double']: item=QStandardItem(b) self.table_model.setItem(row, 0, item) row+=1 self.model_filter_proxy = QSortFilterProxyModel() self.model_filter_proxy.setSourceModel(self.table_model) self.model_filter_proxy.sort(0) self.table_view.setModel(self.model_filter_proxy) # 设置表格选择模式 self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.setStyleSheet("QTableView::item:selected{ background-color: green ; selection-color: white; }") def find_text(self,text): column=0 self.table_view.clearSelection() # 方案1:源模型索引转换 # start = self.table_model.index(0, column) # matches = self.table_model.match( start, Qt.DisplayRole, text, hits=1, flags=Qt.MatchContains ) # if matches: # source_index = matches[0] # proxy_index = self.model_filter_proxy.mapFromSource(source_index) # self.table_view.selectRow(proxy_index.row()) # 方案2:直接在代理模型匹配(推荐) start = self.model_filter_proxy.index(0, column) matches = self.model_filter_proxy.match(start, Qt.DisplayRole, text, hits=1, flags=Qt.MatchContains) if matches: self.table_view.selectRow(matches[0].row()) if __name__ == '__main__': import sys app = QApplication(sys.argv) app.setStyle("fusion") w=MainWindow() w.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者RBenet
相关产品推荐
相关产品推荐

