GTK 4 中列表的更多内容

上一篇文章介绍了 3.98.5 版本中引入的整体列表视图框架,并展示了一些示例。在这篇文章中,我们将深入探讨一些技术领域,并研究一些相关主题。

GtkTreeView 的一个重要特性是它可以显示树。毕竟,这就是它的名字的由来。GtkListView 侧重于普通列表,并使处理这些列表更加容易。特别是,GListModel API 比 GtkTreeModel 简单得多——这就是为什么自定义树模型实现相对较少的原因,但 GTK 4 已经有了大量的列表模型。

但有时我们仍然需要显示树。这其中有一些复杂性,但我们已经找到了一种方法来实现它。

模型

我们需要的第一个要素是一个模型。由于 GListModel 表示项目的线性列表,我们必须更加努力地使其处理树。

GtkTreeListModel 通过添加一种方法来展开项目,按需创建新的子列表模型来实现这一点。GtkTreeListModel 中的项目是 GtkTreeListRow 的实例,它包装了模型中的实际项目,并且有一些函数(如 gtk_tree_list_row_get_children())来获取子模型的项目,以及 gtk_tree_list_row_get_item() 来获取原始项目。GtkTreeListRow 有一个 :expanded 属性,用于跟踪当前是否显示子项。

树列表模型的核心是 GtkTreeListModelCreateModelFunc,它接受列表中的一个项目,并返回一个新的列表模型,其中包含应为树中给定项目的子项的相同类型的项目。

这是一个 GSettings 对象树列表模型的示例。该函数枚举给定 GSettings 对象的子设置,并为它们返回一个新的列表模型。

static GListModel *
create_settings_model (gpointer item,
                       gpointer unused)
{
  GSettings *settings = item;
  char **schemas;
  GListStore *result;
  guint i;

  schemas = g_settings_list_children (settings);

  if (schemas == NULL || schemas[0] == NULL)
    {
      g_free (schemas);
      return NULL;
    }

  result = g_list_store_new (G_TYPE_SETTINGS);
  for (i = 0; schemas[i] != NULL; i++)
    {
      GSettings *child = g_settings_get_child (settings, schemas[i]);
      g_list_store_append (result, child);
      g_object_unref (child);
    }

  g_strfreev (schemas);

  return G_LIST_MODEL (result);
}

展开器

我们需要的下一个要素是一个显示展开器箭头的部件,用户可以单击它来控制 :expanded 属性。这由 GtkTreeExpander 部件提供。正如 GtkTreeListRow 项目包装模型中的底层项目一样,您可以使用 GtkTreeExpander 部件来包装用于显示项目的部件。

以下是树展开器在我们的 GSettings 示例中的实际效果

完整示例可以在这里找到。

排序

在我们离开树之前要谈的最后一个主题是排序。列表通常有多种排序方式:a-z、z-a、忽略大小写等等。列视图通过允许您将排序器与列关联来支持此功能,用户可以通过单击列标题来激活排序器。此 API 是

gtk_column_view_column_set_sorter (column, sorter)

在对树进行排序时,您通常希望排序顺序应用于树中给定级别的项目,而不是跨级别应用,因为那样会打乱树结构。GTK 通过 GtkTreeListRowSorter 支持此功能,它包装了现有的排序器并使其遵守树结构

sorter = gtk_column_view_get_sorter (view);
tree_sorter = gtk_tree_list_row_sorter_new (sorter);
sort_model = gtk_sort_list_model_new (tree_model,           
                                      tree_sorter);
gtk_column_view_set_model (view, sort_model);

总之,在新的列表部件中,树的重要性有所降低,它们为机制增加了很多复杂性,但它们在列表视图和列视图中都得到了完全支持

组合框

单元格渲染器使用的更麻烦的领域之一是我们的单选控件:GtkComboBox。这从来都不是一个好的选择,特别是与嵌套菜单结合使用时。因此,我们渴望在新列表视图机制上尝试 GtkComboBox 的替代品。

从设计方面来看,人们也一直希望组合框能够做得更好,正如这个 2015 年的模拟图所见

五年后,我们终于有了一个替代部件。它被称为 GtkDropDown。新部件的 API 尽可能简单,几乎所有工作都由列表模型和项目工厂机制完成。基本上,您可以使用 gtk_drop_down_new() 创建一个下拉列表,然后为其提供一个工厂和一个模型,就完成了。

由于大多数选项都由简单的字符串组成,因此有一个方便的方法可以从字符串数组中为您创建模型和工厂。

const char * const times[] = {
  "1 minute",
  "2 minutes",
  "5 minutes",
  "20 minutes",
  NULL
};

button = drop_down_new ();
gtk_drop_down_set_from_strings (GTK_DROP_DOWN (button), times);

此便捷 API 与 GtkComboBoxText 非常相似,GtkBuilder 支持也非常相似。您可以在 ui 文件中指定一个字符串列表,如下所示

<object class="GtkDropDown">
  <items>
    <item translatable="yes">Factory</item>
    <item translatable="yes">Home</item>
    <item translatable="yes">Subway</item>
  </items>
</object>

以下是一些正在使用的 GtkDropDown

总结

再次强调这一点:所有这些都是全新的 API,我们很乐意听到您对哪些工作正常、哪些工作不正常以及缺少哪些方面的反馈。