QAbstractItemModel:为什么在将大量项目插入模型时发出 dataChanged 和插入行信号如此缓慢?

ksm*_*ing 2 c++ xml qt qabstractitemmodel

Stackoverflow 中的所有 Qt 模型/视图编程专家大家好。我正在从事的项目要求我为 XML 数据定义一个 QAbstractItemModel 派生模型。当我在实现这个模型的过程中遇到问题时,我之前在这里问过一个问题: QSortFilterProxyModel crashes when Delete a row from the source model via the source model function

该模型目前在应用程序中运行得很好,除了一些我不知道如何解决的性能问题。该应用程序的功能之一是通过设置 Max Num 和 Rand 编号来添加 Frame 元素 xml 节点。每个帧元素将具有分别从 0 到 MaxNum - 1 和 0 到 MaxRand-1 的 Num 和 Rand 编号。此外,我需要为 Rand=0 和 Rand=MaxRand-1 元素分别添加一个子参数元素。简要说明如下:

For Max Num=100, Max Rand=50

<Frame Num="0" Rand="0">
  <Parameter Value="false"/>
 </Frame>
 <Frame Num="0" Rand="1"/>
 <Frame Num="0" Rand="2"/>
 ...
 <Frame Num="0" Rand="48"/>
 <Frame Num="0" Rand="49">
  <Parameter Value="true"/>
 </Frame>
 <Frame Num="1" Rand="0">
  <Parameter Value="false"/>
 </Frame>
 <Frame Num="1" Rand="1"/>
 <Frame Num="1" Rand="2"/>
 ...
 <Frame Num="1" Rand="48"/>
 <Frame Num="1" Rand="49">
  <Parameter Value="true"/>
 </Frame> 
...
<Frame Num="99" Rand="0">
  <Parameter Value="false"/>
 </Frame>
 <Frame Num="99" Rand="1"/>
 <Frame Num="99" Rand="2"/>
 ...
 <Frame Num="99" Rand="48"/>
 <Frame Num="99" Rand="49">
  <Parameter Value="true"/>
 </Frame>
Run Code Online (Sandbox Code Playgroud)

当 MaxNum 和 MaxRand 都很小时(即 Frame 元素总数约为 50)时,应用程序运行良好。但是,当元素计数超过 500 左右时,通过 QAbstractItemModel 函数添加 Frame 元素会变得非常痛苦且呈指数级缓慢。GUI 冻结了很长一段时间,以至于我大部分时间都放弃了等待。

主要更新:

我已经找出了在模型中插入大量(例如 1000 个)项目时导致速度变慢的原因。我在每个插入的项目上调用一次 insertRow(row,parent) 和 setData() ,由于这些函数内部发出的信号,这非常昂贵。

我已将代码修改为 insertRows(row, 1000, Parent) 并定义了一个新的silentSetData(),它不会发出 dataChanged(currIndex, currIndex)。我还添加了一个名为 notificationDataChanges(startRow, endRow, ParentIndex) 的新公共函数,该函数依次针对给定的数据范围发出一次 dataChanged 信号。一切都很好,但现在调用者类需要在插入整组数据后显式调用notifyDataChanges。

现在我想知道为什么发出 dataChanged 信号如此昂贵?一次在模型中插入/更改大量项目时,是否有人尝试过其他方法来解决这个问题?

Neo*_*eox 5

另一种方法是显式重置模型数据结构。例如,在我的一个模型中,数据用QStringList. 我已经实现了一个重置​​模型中数据的函数。例如:

void MyModel:setNewData(const QStringList newList) {

  beginResetModel();

  m_dataList = newList;

  endResetModel();
}
Run Code Online (Sandbox Code Playgroud)

我想这种方法也适用于您的情况。