我正在尝试在Qt中创建QTableView
,这对于大型表来说非常有效。我通过定义自己的抽象表模型设法使数据显示更有效:
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
class DataTableModel(QtCore.QAbstractTableModel):
def columnCount(self, index=None):
return 3
def rowCount(self, index=None):
return 10000
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
return 'c'
elif orientation == Qt.Vertical:
return 'r'
def data(self, index, role):
if not index.isValid():
return None
if role == Qt.DisplayRole:
return "({0},{1})".format(index.row(), index.column())
app = QtGui.QApplication([""])
viewer = QtGui.QTableView()
model = DataTableModel()
viewer.setModel(model)
viewer.show()
这样可以正常工作,因为data
方法仅针对出现在表格视野中的单元格调用。
我现在想要显示某些部分行的现有选择:
import numpy as np
selected_rows = np.where(np.random.random(10000) > 0.5)[0]
我可以通过例如:
告诉表格小部件这个选择smodel = viewer.selectionModel()
for row in selected_rows:
model_index = model.createIndex(row, 0)
smodel.select(model_index, QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows)
然而,这是非常低效的。选择1000-2000行通常需要一秒钟,实际上我有数百万行的表。可能有加速这个循环的方法,但我想完全取消循环,而是让Qt只询问我(类似于数据本身)有关可见单元格内选择的信息。这是可能的,如果是这样,实现这个目标的最佳方法是什么?
答案 0 :(得分:1)
最简单的方法是重新实现选择模型。视图查询选择模型以获取每个索引的选择状态。唉,QItemSelectionModel
有一个主要缺点:你无法重新实现其isSelected
方法。
您可以做的最好的事情是在模型上创建一个新的选择模型,可能没有附加到任何视图,然后选择那里的项目,最后在视图上设置模型和选择模型。
这是API的缺点。
如果这是一个专业项目,你应该在你自己的git版本控制下编译你自己的Qt副本,并且使isSelected
方法虚拟是一种微不足道的方式。
答案 1 :(得分:1)
您应该使用select
的第二个重载版本,即接受QItemSelection
而不是单个索引的版本。
QItemSelection
可以通过为构造函数提供两个参数来选择行的范围:
QItemSelection(start_index, stop_index)
此外,您可以merge
项目成为单一选择:
selection.merge(other_selection, flags)
这表明:
itertools.groupby
将连续的行组合在一起createIndex
获取这些组的所有起始终端索引的QModelIndex
QItemSelection
个对象QItemSelection
合并为一个QItemSelection
请注意,您希望按索引对行进行排序,而不是按其值排序。
答案 2 :(得分:0)
如果要显示某些选定的行,则只显示相反的行 显示所有内容并选择一些行,然后QSortFilterProxyModel可以提供帮助:
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
import numpy as np
class FilterProxy(QtGui.QSortFilterProxyModel):
afilter = set(np.where(np.random.random(10000) > 0.5)[0])
def updateFilter(self, new_filter):
self.afilter = new_filter
self.invalidateFilter()
def filterAcceptsRow(self, row, parent):
if not self.afilter:
return True
return row in self.afilter
class DataTableModel(QtCore.QAbstractTableModel):
def columnCount(self, index=None):
return 3
def rowCount(self, index=None):
return 10000
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
return 'c'
elif orientation == Qt.Vertical:
return 'r'
def data(self, index, role):
if not index.isValid():
return None
if role == Qt.DisplayRole:
return "({0},{1})".format(index.row(), index.column())
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.viewer = QtGui.QTableView()
self.setCentralWidget(self.viewer)
self.action = QtGui.QAction("Filter x > 0.5", self)
self.action.triggered.connect(self.updateFilter)
self.addToolBar("Ffilter").addAction(self.action)
self.model = DataTableModel()
self.proxyModel = FilterProxy(self.viewer)
self.proxyModel.setDynamicSortFilter(True)
self.proxyModel.setSourceModel(self.model)
self.viewer.setModel(self.proxyModel)
def updateFilter(self):
new_max = np.random.rand(1)[0]
new_filter = set(np.where(np.random.random(10000) > new_max)[0])
self.action.setText("Filter x > {} N = {}".format(new_max, len(new_filter)))
self.proxyModel.updateFilter(new_filter)
app = QtGui.QApplication([""])
viewer = MyWindow()
viewer.show()
app.exec_()