GTK 2/3是否支持高效的虚拟表?

时间:2017-05-03 08:25:55

标签: java gtk virtual gtk3 gtk2

我们正在使用SWT开发一个Java应用程序,它提供了虚拟表。允许在100和10M之间切换表行数的测试代码在Windows和OSX上的工作时间不到100毫秒,但在Ubuntu 16.04上需要几秒钟。现在我们想知道这是否是SWT GTK实施或GTK本身的缺点?在后一种情况下,GTK 2和GTK 3之间是否存在差异?

1 个答案:

答案 0 :(得分:3)

TLDR:不幸的是,GTK的GtkTreeView似乎根本不支持虚拟模式,而且它的实现方式对于大量项目效率非常低。 SWT选择使用Table实施GtkTreeView并引入了进一步的性能问题。

SWT Table.setItemCount()

Table.setItemCount()的来源:

  • 存储库:http://git.eclipse.org/gitroot/platform/eclipse.platform.swt.git
  • 源文件:eclipse.platform.swt\bundles\org.eclipse.swt\Eclipse SWT\gtk\org\eclipse\swt\widgets\Table.java
  • 查找:public void setItemCount (int count) {

您会看到即使在VIRTUAL模式下,setItemCount也会使用OS.gtk_list_store_append()分配所有项目,一次一个:

for (int i=itemCount; i<count; i++) {
    OS.gtk_list_store_append (modelHandle, iter);
}

SWT OS.gtk_list_store_append

OS.gtk_list_store_append的来源:

  • 存储库:http://git.eclipse.org/gitroot/platform/eclipse.platform.swt.git
  • 源文件:eclipse.platform.swt\bundles\org.eclipse.swt\Eclipse SWT\gtk\org\eclipse\swt\widgets\Table.java
  • 查找:public static final void gtk_list_store_append(long /*int*/ list_store, long /*int*/ iter) {

这里,对于每个项目,获取并释放锁定并调用本机方法。我猜他们应该至少用一个原生呼叫分配所有项目。

public static final void gtk_list_store_append(long /*int*/ list_store, long /*int*/ iter) {
    lock.lock();
    try {
        _gtk_list_store_append(list_store, iter);
    } finally {
        lock.unlock();
    }
}

GTK gtk_list_store_append

  • 存储库:git://git.gnome.org/gtk+
  • 源文件:gtk/gtkliststore.c
  • 查找:gtk_list_store_append (GtkListStore *list_store,

它只是调用gtk_list_store_insert(list_store, iter, -1)

GTK gtk_list_store_insert

  • 存储库:git://git.gnome.org/gtk+
  • 源文件:gtk/gtkliststore.c
  • 查找:gtk_list_store_insert (GtkListStore *list_store,

关键操作是g_sequence_insert_before,插入gsequence,这是一棵平衡树。

void
gtk_list_store_insert (GtkListStore *list_store,
               GtkTreeIter  *iter,
               gint          position)
{
  GtkListStorePrivate *priv;
  GtkTreePath *path;
  GSequence *seq;
  GSequenceIter *ptr;
  gint length;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);

  priv = list_store->priv;

  priv->columns_dirty = TRUE;

  seq = priv->seq;

  length = g_sequence_get_length (seq);
  if (position > length || position < 0)
    position = length;

  ptr = g_sequence_get_iter_at_pos (seq, position);
  ptr = g_sequence_insert_before (ptr, NULL);

  iter->stamp = priv->stamp;
  iter->user_data = ptr;

  g_assert (iter_is_valid (iter, list_store));

  priv->length++;

  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
  gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
  gtk_tree_path_free (path);
}

不幸的是,这个函数很多在批量插入过程中不需要的东西,例如它每次计算序列的长度(具有非常复杂的时间复杂度),将索引转换为迭代器,触发树的更新通知等等。

我搜索过,但没有找到任何批量插入内容。

Windows实施

Table的Windows实现使用操作系统提供的ListView控件,该控件在虚拟模式下有效实现(参见LVS_OWNERDATA

另请参阅:Eclipse Bug 236863