GTK 4 中的自定义小部件 – 布局

(这是关于 GTK 4 中自定义小部件的系列文章的第三部分。 第一部分第二部分)。

推荐使用小部件

正如我们之前所说,“一切都是小部件”。例如,我们建议您使用 GtkLabel 而不是手动渲染 pango 布局,或者使用 GtkImage 而不是手动加载和渲染 pixbuf。使用现成的小部件可以确保您获得所有预期的行为,例如选择处理、上下文菜单或高 DPI 支持。而且这比您自己完成所有操作要容易得多。

委托布局

snapshot() 和 measure() 函数的默认实现会自动处理子小部件。自定义小部件的主要职责是根据需要排列子小部件。在 GTK 3 中,这将通过实现 size_allocate() 函数来完成。您仍然可以这样做。但在 GTK 4 中,更方便的替代方法是使用布局管理器。GTK 提供了许多预定义的布局管理器,例如 GtkBoxLayout、GtkCenterLayout、GtkGridLayout 等。

可以通过多种方式设置布局管理器,最简单的方法是在 class_init 函数中设置布局管理器类型

gtk_widget_class_set_layout_manager_type (widget_class, 
                                          GTK_TYPE_GRID_LAYOUT);

然后,GTK 将自动实例化并使用这种类型的布局管理器。

布局管理器将其子小部件包装在它们自己的“布局子”对象中,这些对象可以具有影响布局的属性。这是子属性的替代方案。就像子属性一样,您可以在 ui 文件中设置这些“布局属性”

<child>
  <object class="GtkLabel">
    <property name="label">Image:</property>
    <layout>
      <property name="left-attach">0</property>
    </layout>
  </object>
</child>

添加子项

使用模板是将子项添加到小部件的最便捷方式。在 GTK 4 中,这适用于任何小部件,而不仅仅是容器。如果出于某种原因,您需要手动创建子小部件,则最好在 init() 函数中完成

void
demo_init (DemoWidget *demo)
{
  demo->label = gtk_label_new ("Image:");
  gtk_widget_set_parent (demo->label, GTK_WIDGET (demo));
}

执行此操作时,重要的是设置正确的父子关系,使您的子小部件成为整体小部件层次结构的一部分。并且需要在 dispose() 函数中撤消此设置

void
demo_dispose (GObject *object)
{
  DemoWidget *demo = DEMO_WIDGET (object);

  g_clear_pointer (&demo->label, gtk_widget_unparent);

  GTK_WIDGET_CLASS (demo_widget_parent_class)->dispose (object);
}

新的可能性

布局管理器很好地将布局任务与小部件机制的其余部分隔离,这使得试验新的布局更容易。

例如,GTK 4 包括 GtkConstraintLayout,它使用约束求解器根据小部件大小和位置的一组约束创建布局。

要了解有关 GTK 4 中约束的更多信息,请阅读 GtkConstraintLayout 的文档。

展望

在下一篇文章中,我们将了解 GTK 4 中的小部件如何处理输入。