创建没有容器作为父级的 Gtk 复合对象

Posted

技术标签:

【中文标题】创建没有容器作为父级的 Gtk 复合对象【英文标题】:Create Gtk composite object that doesn't have a container as a parent 【发布时间】:2021-12-29 22:18:21 【问题描述】:

例如,我想创建一个非常简单的 Gtk 复合对象,它是 GtkBox 中的 GtkButton。而已。我们就叫它BoxedButon

但是,我希望它具有 GtkButton 的界面。相同的属性、信号、方法等。

如果我派生一个父类为GTK_TYPE_BUTTON 的新类,那么GTK_BUTTON((BoxedButton*)a_boxed_button_instance) 将起作用。它实际上具有按钮的界面。

但它不能添加到容器中,因为当添加BoxedButton 时,它会尝试添加与GtkButton 对应的GtkWidget,它已经在GtkBox 中,即BoxedButton也包含。

如果该类是从GTK_TYPE_BOX 的父类派生的,则将其添加到容器中是可行的。但它没有GtkButton 的接口。每个属性、信号、gtk_button_* 方法等都需要复制。这比新类需要做的任何其他事情都要多一个数量级的代码。

我想也许我可以覆盖set_parent(),以便它设置盒子的父代。但是GtkBoxClass 没有set_parent(),因此显然将小部件添加到渲染层次结构中发生的任何事情都不能被覆盖。

有什么方法可以不涉及数百行代码吗?

【问题讨论】:

使用您的第一个解决方案:也许您可以先转换为GtkBox,然后再调用add 它不是从 GtkBox 派生的,因此无法转换为该类型。 也许如果有办法在 gobject 中进行多重继承,它可以从两者派生,但我认为这是可能的。 好的,抱歉我误会了。它的组成。那么也许是 GtkBox 的吸气剂? 【参考方案1】:

我想出了两种方法来做到这一点,但似乎都不理想。

首先是从我们想要将复合对象视为一种类型的对象类型中派生出复合小部件。在这种情况下,我们从GtkButton 派生对象,因为我们想将其视为一种按钮并继承缓冲区的接口。然后创建一个实例方法来获取任何小部件是复合小部件布局层次结构的顶层。例如:

GtkWidget *boxed_button_get_toplevel(BoxedButton *bb)

    BoxedButtonPrivate *priv = boxed_button_get_instance_private(bb);
    return GTK_WIDGET(priv->top_level_box);

将复合对象添加到容器时,此方法用于获取要添加的对象。例如:

GtkWidget *bb = boxed_button_new();
gtk_container_add(some_container, boxed_button_get_toplevel(BOXED_BUTTON(bb)));
gtk_button_set_label(GTK_BUTTON(bb), "Label");

这很容易实现和使用,但没有其他 Gtk 小部件以这种方式工作。小部件本身总是添加到容器中。

所以我们得到了另一种选择,即从***容器的类型派生对象,例如来自GtkBox。然后创建一个实例方法来获取我们应该将复合小部件视为一种类型的小部件,例如GtkButton. 现在我们的代码更像这样:

GtkButton *boxed_button_get_button(BoxedButton *bb)

    BoxedButtonPrivate *priv = boxed_button_get_instance_private(bb);
    return GTK_BUTTON(priv->contained_button);

GtkWidget *bb = boxed_button_new();
gtk_container_add(some_container), GTK_WIDGET(boxed_button_get_button(BOXED_BUTTON(bb))));
gtk_button_set_label(boxed_button_get_button(BOXED_BUTTON(bb)), "Label");

这可能更麻烦,因为使用复合作为小部件作为按钮的调用可能比将其添加到容器中的调用要多得多。还有一个明显的缺点。不能添加或覆盖GtkButton 提供的属性或信号。将为复合对象定义新的属性和信号,而GtkButton 的属性和信号将由按钮定义且无法更改。

【讨论】:

您的第一个解决方案是我认为最好的解决方案。最简单和最可维护的。请注意,确实没有其他 Gtk 小部件以这种方式工作,但是也没有原生 Gtk 小部件以这种方式构造。【参考方案2】:

为了完整起见,还有第三种方法;继承自 GtkBox 并代理 GtkButton 的所有方法。这在 C 语言中会非常冗长,并且仍然无法为您提供使用 GtkButton 界面的便利(您必须编写 boxed_button_set_label(...))但是如果您使用语言绑定中的小部件,这可能是最简单的方法.

【讨论】:

以上是关于创建没有容器作为父级的 Gtk 复合对象的主要内容,如果未能解决你的问题,请参考以下文章

百度联盟广告如何理解按父容器宽度

获取父级的高度

Vuejs 中从子级到父级的事件监听

nhibernate - 通过更新父级或显式创建来创建子级?

创建 API 网关资源的 Terraform 错误抱怨具有相同父级的另一个资源已经具有此名称

如何从UserControl访问父级的DataContext