wxDataViewListCtrl 很慢,来自另一个线程的 100k 个项目

wxDataViewListCtrl is slow with 100k items from another thread

要求:

  1. 10 万行
  2. 其中一列不是文本 - 它是用 wxDC* 自定义绘制的。
  3. 项目添加来自另一个使用 wxThreadEvent 的线程。

我唯一能想到的就是使用wxDataViewCtrl + wxDataViewModel。但是我不明白如何添加项目。

我查看了示例 (https://github.com/wxWidgets/wxWidgets/tree/WX_3_0_BRANCH/samples/dataview),对我来说太复杂了。 我听不懂。

我看了 wiki (https://wiki.wxwidgets.org/WxDataViewCtrl),对我来说也太复杂了。

有人可以提供一个非常简单的 wxDataViewCtrl + wxDataViewModel 示例,其中包含一个字符串列和一个 wxDC* 列。

提前致谢。

P.S.

根据 @HajoKirchhoff 在评论中的要求,我发布了一些代码:

// This is called from Rust 100k times.
extern "C" void Add_line_to_data_view_list_control(unsigned int index,
                                                   const char* date,
                                                   const char* sha1) {
    wxThreadEvent evt(wxEVT_THREAD, 44);
    evt.SetPayload(ViewListLine{index, std::string(date), std::string(sha1)});
    wxQueueEvent(g_this, evt.Clone());
}

void TreeWidget::Add_line_to_data_view_list_control(wxThreadEvent& event) {
    ViewListLine view_list_line = event.GetPayload<ViewListLine>();

    wxVector<wxVariant> item;

    item.push_back(wxVariant(static_cast<int>(view_list_line.index)));
    item.push_back(wxVariant(view_list_line.date));
    item.push_back(wxVariant(view_list_line.sha1));

    AppendItem(item);
}

将 10 万个项目附加到控件总是很慢。那是因为它需要将 100k 项目从您的存储移动到控件存储。对于这种数据量,更好的方法是拥有一个“虚拟”列表控件或 wxGrid。在这两种情况下,数据实际上并未传输到控件。相反,当绘画发生时,回调函数将仅传输绘画所需的数据。因此,对于 100k 的列表,对于可见的 20-30 行,您将只有“activity”。

wxListCtrlhttps://docs.wxwidgets.org/3.0/classwx_list_ctrl.html,指定wxLC_VIRTUAL标志,调用SetItemCount然后provide/override

  • OnGetItemText
  • OnGetItemImage
  • OnGetItemColumnImage

缺点:您只能绘制包含在 wxImageList 中的项目,因为 OnGetItemImage return 会指示到列表中。所以你不能使用 wxDC 绘制任意项目。由于人眼无论如何都会被 10 万张不同的图像淹没,所以这通常是可以接受的。您可能需要事先提供 20/30 个不同的图像,但您将拥有一个快速、灵活的列表。

也就是说, 可以覆盖 OnPaint 函数并使用 wxDC 绘制列表中的任何内容。但这很快就会变得困难。

所以另一种方法是使用 wxGrid,创建一个 wxGridTableBase 派生的 class 作为网格和实际 100k 数据之间的桥梁,并创建 wxGridCellRenderer 派生 classes 以在屏幕上呈现实际数据。 wxGridCellRenderer class 将得到 wxDC。这将为您提供更大的灵活性,但也比使用虚拟 wxListCtrl 复杂得多。

随心所欲的完整示例难免比较复杂。但是如果你分解成简单的部分,其实并没有那么难:你确实需要定义一个自定义模型,但如果你的列表是扁平的,这基本上只是意味着返回 N-th 位置的项目的值,如您可以轻松实现与树结构相关的所有模型方法。这种模型的一个例子,虽然在示例中可以找到多列,所以你只需要将它简化为一个(或两个)列版本。

接下来,您还需要一个自定义渲染器,但这也不难,同样,示例中也有这样的示例。

如果您有任何具体问题,您应该提出来,但是很难比示例显示的更好,而且它已经准确地显示了您想要做的事情。

谢谢大家的回复!

@Vz. 的话“如果你有任何具体问题,你应该问他们”让我开始思考,我又看了看wxWidgets的示例。可以找到完整代码 here。看下面类:

  1. TreeDataViewModel
  2. TreeWidget
  3. TreeCustomRenderer