【问题标题】:Is there a better way to update tableview model in PyQt5?有没有更好的方法来更新 PyQt5 中的 tableview 模型?
【发布时间】:2021-06-27 11:38:21
【问题描述】:

我有一个包含 6 列的表,其中包含 4 个不同的数据集。第 1 列和第 3 列每秒更新 10 次,第 2 列是静态列,在初始化时更新一次,然后不再更新。其他列的更新频率较低。我有点滞后 - 不可怕但绝对明显。

为了更新数据,我正在使用beingResetModel 和endResetModel。从文档中我了解到这将清除表格,然后为每个可见(行、列)调用数据。我正在更新很多我不需要的数据。

有没有一种方法可以指定我在更新函数中更改哪些列?是否可以只更新 column2 一次,然后再也不更新?

一个简化的模型如下所示,实际上数据结构不同,某些列的索引更复杂

class TableModel(PyQt5.QtCore.QAbstractTableModel):
    def __init__(self, specs, length = 100000, parent=None):
        super().__init__(parent)
        self.default_length = length

        self.initData()
        

    def rowCount(self, parent=PyQt5.QtCore.QModelIndex()):
        return self.default_length

    def columnCount(self, parent=PyQt5.QtCore.QModelIndex()):
        return 6

        
    def update_d1(self, dat1):
        #changes data in column 1 and 3
        #data updates 10x per second
        self.beginResetModel()
        self.dat1 = dat1
        self.endResetModel()

    def update_d2(self, middle):
        #changes data in column 2
        #data updates once on initialisation, column doesnt change thereafter
        self.beginResetModel()
        self.middle = middle
        self.endResetModel()

    def update_d3(self, dat3):
        #changes data in column 5
        #data updates twice every second
        self.beginResetModel()
        self.dat3 = dat3
        self.endResetModel()

    def update_d4(self, dat4):
        #changes column 0 and 4
        # data updates sporadically
        self.beginResetModel()
        self.col0 = dat4['col0']
        self.col4 = dat4['col4']
        self.endResetModel()

    def data(self, index, role):
        if not index.isValid():
            return
        
        if role == PyQt5.QtCore.Qt.DisplayRole:
            if index.row() < 0 or index.row() >= self.default_length:
                return None
            if index.column() == 0:
                val = self.col0[index.row()]
                return val

            if index.column() == 4:
                val = self.col4[index.row()]
                return val

            if index.column() == 2:
                return self.middle[index.row()]
            if index.column() == 1:
                val = self.dat1['col1'][index.row()]
                return val

            if index.column() == 3:
                val = self.dat1['col3'][index.row()]
                return val

            if index.column() == 5:
                #print(self.volume_profile)
                val = self.dat3[index.row()]
                return val

编辑

如果我更改为以下内容,它将仅更新第一列中的第 100 行。

def update_d1(self, dat1):
    col1_start_index = self.index(100, 0)
    col1_end_index = self.index(100, 0)
    self.data = data
    self.dataChanged.emit(col1_start_index, col1_end_index)

如果我将结束索引设置为第 101 行,整个表格将再次更新,而不仅仅是 2 个单元格。提供两个索引的目的是什么?

def update_d1(self, dat1):
    col1_start_index = self.index(100, 0)
    col1_end_index = self.index(101, 0)
    self.data = data
    self.dataChanged.emit(col1_start_index, col1_end_index)

【问题讨论】:

  • 如果你只是更新数据,模型大小没有改变,你为什么要使用beingResetModel开始呢?您已经阅读了有关它的文档,很明显该功能不是您需要的,您是否考虑过阅读文档的其余部分来寻找什么你需要吗?
  • 感谢 musica,请参阅我对 dataChanged 的​​编辑。
  • 这是所有项目视图的默认行为:只要 topLeft 和 bottomRight 索引不匹配,视图就会得到 full 更新(参见 source code。可能的解决方法可能是为模型创建一个自定义信号并将其连接到仅更新范围内索引的函数。
  • 自定义信号的效率是否等同于循环开始和结束索引并为每个索引发出 dataChanged?
  • 理论上不会:这仅取决于您如何发出这些信号。如果它们在同一个事件循环中发出(简化,dataChange 信号都是从同一个函数调用发送的,包括任何递归级别)它不会改变那么多:结果是该视图将为 dataChanged 索引的每个visualRect 安排更新。您可以尝试通过“分组”所有更改的索引并使用这些索引发出信号来进行某种程度的优化,然后在连接的视图函数中使用visualRect 创建一个包含所有这些索引矩形的 QRegion。

标签: python qt user-interface pyqt5 pyside


【解决方案1】:

您应该改为发出dataChanged(const QModelIndex &amp;topLeft, const QModelIndex &amp;bottomRight, const QVector&lt;int&gt; &amp;roles = QVector&lt;int&gt;()) 信号。 beginXxx 和 endXxx API 用于 structural 变化,其中模型的 shape 发生变化。由于您只是更改模型的内容(或数据) - 在这种情况下不要使用结构化 API。

【讨论】:

  • 感谢 Kuba,看看我对这个实现的编辑吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-22
  • 2019-09-03
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多