(这是关于 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 中的小部件如何处理输入。