PyQt5 中 QSortFilterProxyModel 的使用示例代码
时间: 2025-07-01 11:27:53 浏览: 8
<think>好的,我现在需要处理用户关于PyQt5中QSortFilterProxyModel的示例代码和教程的请求。首先,用户提到了他们在使用QTableView和QSortFilterProxyModel时遇到了行号错乱的问题,并提供了一个C++的示例代码。他们现在想寻找PyQt5的相关示例。
首先,我需要回忆QSortFilterProxyModel在PyQt5中的作用。它主要用于对源模型的数据进行排序、过滤,而不改变源模型本身的结构。这在处理表格视图时非常有用,比如在QTableView中显示经过排序或过滤后的数据,同时保持源数据的完整性。
接下来,用户需要的是示例代码和使用教程。我应该先提供一个基本的示例,展示如何在PyQt5中创建源模型(比如QStandardItemModel),然后设置QSortFilterProxyModel,并将其应用到QTableView上。示例代码需要包括排序和过滤的功能,比如通过输入框进行实时过滤。
然后,我需要确保代码的语法正确,符合PyQt5的规范。例如,在PyQt5中,信号和槽的连接方式可能与C++有所不同,使用lambda函数或者装饰器。同时,需要注意模型索引的映射,特别是在处理点击事件时,需要将代理模型的索引映射回源模型,以获取正确的行号和数据。这一点用户已经在C++代码中提到了,所以在PyQt5的示例中也需要包含类似的逻辑。
另外,用户提供的引用[^1]是关于QTableView在使用QSortFilterProxyModel后行号错乱的问题。这说明用户可能遇到了在代理模型中使用行号时的混淆,因此示例代码中需要明确展示如何正确获取源模型的行号和数据。例如,在点击单元格时,使用mapToSource方法将代理索引转换为源索引,然后获取行号和数据。
在教程部分,我需要分步骤解释代码的结构,包括创建源模型、设置代理模型、视图的关联,以及如何实现排序和过滤功能。同时,要强调处理用户交互时索引映射的重要性,避免行号错误的问题。此外,可能还需要提到一些常见问题,比如动态过滤、自定义排序规则,以及如何维护源模型的正确引用。
最后,生成相关问题需要考虑用户可能进一步的需求,比如动态过滤的实现、自定义排序、维护源模型索引,以及性能优化的方法。这些问题可以帮助用户更深入地理解QSortFilterProxyModel的应用和潜在问题的解决方法。
总结来说,我需要构建一个结构清晰的PyQt5示例,包含必要的代码和解释,确保用户能够理解并正确应用QSortFilterProxyModel,同时避免常见的行号错乱问题。此外,提供相关问题以引导用户进一步探索相关主题。</think>以下是一个PyQt5中使用$QSortFilterProxyModel$的完整示例代码及分步说明,重点解决代理模型与源模型的行号映射问题:
### 示例代码
```python
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class DemoWindow(QWidget):
def __init__(self):
super().__init__()
# 创建源模型
self.source_model = QStandardItemModel(5, 3)
for row in range(5):
for col in range(3):
item = QStandardItem(f"Row{row}-Col{col}")
self.source_model.setItem(row, col, item)
# 创建代理模型
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.source_model)
# 创建视图
self.table = QTableView()
self.table.setModel(self.proxy_model)
self.table.clicked.connect(self.on_cell_click)
# 创建过滤输入框
self.filter_input = QLineEdit()
self.filter_input.textChanged.connect(self.apply_filter)
# 创建排序按钮
self.sort_btn = QPushButton("按第0列排序")
self.sort_btn.clicked.connect(lambda: self.proxy_model.sort(0))
layout = QVBoxLayout()
layout.addWidget(self.filter_input)
layout.addWidget(self.sort_btn)
layout.addWidget(self.table)
self.setLayout(layout)
def apply_filter(self, text):
self.proxy_model.setFilterRegExp(text)
def on_cell_click(self, proxy_index):
if not proxy_index.isValid():
return
# 映射到源模型索引
source_index = self.proxy_model.mapToSource(proxy_index)
# 获取源模型中的真实行号和数据
real_row = source_index.row()
data = self.source_model.data(source_index)
print(f"源模型行号:{real_row}, 数据:{data}")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DemoWindow()
window.show()
sys.exit(app.exec_())
```
### 关键点解析
1. **模型架构**:
- 源模型($QStandardItemModel$)存储原始数据
- 代理模型($QSortFilterProxyModel$)处理排序和过滤
- 视图($QTableView$)显示代理模型数据[^1]
2. **索引映射**:
- 使用$mapToSource()$将代理索引转换为源模型索引
- 通过源模型索引获取真实行号和数据
3. **核心功能实现**:
```python
# 过滤功能
self.proxy_model.setFilterKeyColumn(0) # 默认过滤第0列
self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
# 动态排序
self.proxy_model.setDynamicSortFilter(True)
```
### 常见问题解决
1. **行号错乱**:必须始终通过$mapToSource()$获取源模型行号,直接使用$proxyIndex.row()$得到的是代理模型中的临时行号
2. **数据访问**:
```python
# 错误方式:直接使用代理索引访问源模型
# data = self.source_model.data(proxy_index)
# 正确方式:映射后访问
source_index = self.proxy_model.mapToSource(proxy_index)
data = self.source_model.data(source_index)
```
3. **自定义过滤**:
```python
class CustomFilterProxy(QSortFilterProxyModel):
def filterAcceptsRow(self, source_row, source_parent):
# 自定义过滤逻辑
return super().filterAcceptsRow(source_row, source_parent)
```
阅读全文
相关推荐


















