在Qt表中选择许多行

时间:2016-08-08 13:01:37

标签: python performance qt pyqt

我正在尝试在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只询问我(类似于数据本身)有关可见单元格内选择的信息。这是可能的,如果是这样,实现这个目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

最简单的方法是重新实现选择模型。视图查询选择模型以获取每个索引的选择状态。唉,QItemSelectionModel有一个主要缺点:你无法重新实现其isSelected方法。

您可以做的最好的事情是在模型上创建一个新的选择模型,可能没有附加到任何视图,然后选择那里的项目,最后在视图上设置模型和选择模型。

这是API的缺点。

如果这是一个专业项目,你应该在你自己的git版本控制下编译你自己的Qt副本,并且使isSelected方法虚拟是一种微不足道的方式。

答案 1 :(得分:1)

您应该使用select的第二个重载版本,即接受QItemSelection而不是单个索引的版本。

QItemSelection可以通过为构造函数提供两个参数来选择行的范围

QItemSelection(start_index, stop_index)

此外,您可以merge项目成为单一选择:

selection.merge(other_selection, flags)

这表明:

  1. 对要选择的行的索引进行排序
  2. 使用itertools.groupby将连续的行组合在一起
  3. 使用createIndex获取这些组的所有起始终端索引的QModelIndex
  4. 为每组行创建QItemSelection个对象
  5. 将所有QItemSelection合并为一个QItemSelection
  6. 对您的模特进行选择。
  7. 请注意,您希望按索引对行进行排序,而不是按其值排序。

答案 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_()