python - 我的实时搜索实现是否滥用了 PyQt5 方法?
问题描述
我一直在做一个管理大型数据集的项目,利用 PyQt5 的 QAbstractTableModel、QTableView 和 QSortFilterProxyModel 类来显示、过滤和修改数据。我将来需要扩展这个项目,所以我会尽力避免不良做法。我目前犹豫要不要继续前进,因为我刚刚实现了一个实时搜索栏(您键入时的表格过滤器),它似乎在测试数据上运行良好,但我担心每次输入键时运行函数可能会导致更大的问题数据集/更复杂的搜索条件。
我通过一个简单的示例复制了下面的实时搜索功能,该示例通过连接 QLineEdit.textChanged 信号在每次将字符输入到搜索栏中时更新代理模型的过滤字符串来过滤表模型中的“名称”列。
如果这里没有真正的问题,我深表歉意,但我找不到此功能的任何 PyQt 示例。我只想知道使用 textChanged 信号更新每个按键上的过滤条件是否安全,或者是否有更好/更有效的方法来完成此操作。
我已经在更大的数据集和稍微复杂的过滤条件上尝试了这个功能,它似乎运行顺利,但我对 PyQt 的熟练程度不足以猜测以后可能会出现什么类型的问题。
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas
import sys
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None):
super().__init__(parent)
self.headings = ["name", "address", "number"]
self.dataset = data
def rowCount(self, parent):
return self.dataset.shape[0]
def columnCount(self, parent):
return self.dataset.shape[0]
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
return self.dataset.iloc[index.row()][index.column()]
return QtCore.QVariant()
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal:
return self.headings[section]
return QtCore.QVariant()
class ProxyTableModel(QtCore.QSortFilterProxyModel):
def __init__(self):
super().__init__()
self.filter_str = ''
def setFilterStr(self, val):
self.filter_str = val.lower()
def filterAcceptsRow(self, sourceRow, sourceParent):
index = self.sourceModel().index(sourceRow, 0, sourceParent)
data = self.sourceModel().data(index, QtCore.Qt.DisplayRole)
return self.filter_str in data.lower()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, data):
super().__init__()
self.setupUi(data)
self.show()
def setupUi(self, data):
self.setObjectName("MainWindow")
self.resize(500, 500)
# create central display widget
self.centralWidget = QtWidgets.QWidget(self)
self.centralWidget.setObjectName("central_widget")
# create table view
self.tableView = QtWidgets.QTableView(self.centralWidget)
self.tableView.setGeometry(QtCore.QRect(0, 50, 500, 450))
self.tableView.setObjectName("email_attributes")
# create models & set proxy model to view
self.mainModel = TableModel(data)
self.proxyModel = ProxyTableModel()
self.proxyModel.setSourceModel(self.mainModel)
self.tableView.setModel(self.proxyModel)
# create column filter search bar
self.searchBar = QtWidgets.QLineEdit(self.centralWidget)
self.searchBar.setGeometry(QtCore.QRect(0, 0, 500, 50))
self.searchBar.textChanged[str].connect(self.filternames)
# set central widget & connect slots
self.setCentralWidget(self.centralWidget)
QtCore.QMetaObject.connectSlotsByName(self)
def filternames(self, text):
# set proxy model filter string
self.proxyModel.setFilterStr(text)
# set filterFixedString() to '' to refresh view
self.proxyModel.setFilterFixedString('')
# underlying dataset for table model
df = {
"name": ["John Smith", "Larry David", "George Washington"],
"address": ["10 Forest Dr", "15 East St", "12 Miami Ln"],
"phone_number": ["000-111-2222", "222-000-1111", "111-222-0000"]
}
data = pandas.DataFrame(df)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = MainWindow(data)
sys.exit(app.exec_())
解决方案
您应该扩展 QLineEdit 类和 keyPressedEvent 函数来处理各种按键事件,如下所示
from PyQt5.QtWidgets import (QLineEdit)
from PyQt5.QtCore import (Qt, QRegExp)
class LineEdit(QLineEdit):
def __init__(self, parent=None):
super(LineEdit, self).__init__(parent)
self.initialize_component()
def initialize_component(self):
self.setClearButtonEnabled(True)
def keyPressEvent(self, event):
key = event.key()
if key == Qt.Key_Tab:
self.parent().focusNextChild()
elif key == Qt.Key_Backtab:
self.parent().focusPrevChild()
else:
return QLineEdit.keyPressEvent(self, event)
推荐阅读
- node.js - nodejs请求发布大json失败
- php - PHP - MYSQL 致命错误:常量表达式包含无效操作
- php - 使用 Snappy PDF 在 linux 中打印 pdf 时出错
- docker - 创建一个 dockerfile 来编译源代码
- java - 如何在 Kotlin 中仅在外部内部限制内部类的实例化?
- neural-network - 如何使用英特尔集成显卡训练神经网络
- c++ - 了解这个高度模板化的 C++ 函数绑定器
- java - 在存储android中保存文本的权限不起作用
- html - CSS:边框线的透明部分
- python - 已安装的模块可从 python3 访问但不能从 2.7 访问?