You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 20:23:12