【问题标题】:Is there a good way to copy a Gtk widget?有没有复制 Gtk 小部件的好方法?
【发布时间】:2010-06-13 08:26:33
【问题描述】:

有没有办法使用 C 中的 Gtk 库来克隆 Gtk 按钮(例如),并将其打包到应用程序的其他位置。我知道你不能两次打包同一个小部件。并且这段代码显然不起作用,但显示了当我尝试按钮的浅拷贝时会发生什么:

GtkButton *a = g_object_new(GTK_TYPE_BUTTON, "label", "o_0", NULL);
GtkButton *b = g_memdup(a, sizeof *a);
gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(b));

周围的代码创建了一个 vbox 并将其打包在一个窗口中并运行 gtk_main()。这将导致这些难以理解的错误消息:

(main:6044): Gtk-CRITICAL **: gtk_widget_hide: assertion `GTK_IS_WIDGET (widget)' failed

(main:6044): Gtk-CRITICAL **: gtk_widget_realize: assertion `GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
**
Gtk:ERROR:/build/buildd/gtk+2.0-2.18.3/gtk/gtkwidget.c:8431:gtk_widget_real_map: assertion failed: (GTK_WIDGET_REALIZED (widget))

同样,如果我要编写自己的 GObject(不一定是 Gtk 小部件),是否有编写复制构造函数的好方法。我认为它应该是一个带有可选钩子的接口,主要基于属性,以某种方式处理类的层次结构。

我想这样做:

GtkButton *b = copyable_copy(COPYABLE(a));

如果 GtkButton 可以使用理论上的可复制接口。

【问题讨论】:

  • 你可以创建一个 GObject 接口,通过提供钩子和东西来完成“可复制”的事情......虽然我不想写它,它可能会很棘手...... .

标签: c gtk copy-constructor gobject


【解决方案1】:

我不这么认为。据我所知,不能保证小部件的所有状态都保存在属性中,您可以从外部访问。如果小部件通过不导出来“隐藏”状态,则您无法从外部复制它。

从技术上讲,小部件可以只在其核心 struct 中包含您在实现之外看不到的字段,因此您甚至无法使用愚蠢的 memcpy() 复制这些位,除非您愿意通过手动计数和使用文字来指定字节数。

话虽如此,也很可能有足够多的小部件通过属性公开足够的状态,副本仍然可以运行,并且可能只会出现小故障。这肯定是一个非常酷的 hack。我建议直接询问核心 GTK+ 开发人员,也许在 gtk-devel-list 邮件列表中。

【讨论】:

  • 谨慎的好答案,但可能不够谨慎!按位复制不起作用,更何况,出于同样的原因,必须在例如C++:因为如果源包含对其他对象的引用,按位复制会创建对这些对象的额外引用,但不会增加它们的引用计数,从而导致释放后使用、双重释放和所有其他可怕的方式。另外,我很确定 GTK+ 开发人员不会对此感兴趣,因为我们在这里给出了原因,而且 IMO 也不应该这样做。
【解决方案2】:

通过属性克隆是一个可行的解决方案:

GObject *
g_object_clone(GObject *src)
{
    GObject *dst;
    GParameter *params;
    GParamSpec **specs;
    guint n, n_specs, n_params;

    specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs);
    params = g_new0(GParameter, n_specs);
    n_params = 0;

    for (n = 0; n < n_specs; ++n)
        if (strcmp(specs[n]->name, "parent") &&
            (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
            params[n_params].name = g_intern_string(specs[n]->name);
            g_value_init(&params[n_params].value, specs[n]->value_type);
            g_object_get_property(src, specs[n]->name, &params[n_params].value);
            ++ n_params;
        }

    dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params);
    g_free(specs);
    g_free(params);

    return dst;
}

虽然克隆一个小部件并不是那么简单,但上述方法在大多数情况下都是可用的(肯定是在GtkButton 上)。

我不在乎很多没有通过属性公开的状态(所有适当的小部件都应该完全由属性定义,以便与GtkBuilder 一起使用),但是很多极端情况会使健壮的克隆变得非常困难(接口和容器是我最先想到的)。

【讨论】:

  • 谢谢,这对于 GObject 上的通用复制构造函数来说是最好的(并且可以满足我的需要)。
  • 你也不想设置GtkWidget::marginGtkWidget::expand属性;它们会覆盖其他属性。
  • 虽然这可能似乎与您测试的一样有效,但从向人们提出的安全建议的意义上说,它不是“可行的”,因为另一个答案及其cmets中给出了多种原因。因此,它不是“GObject 上的通用复制构造函数可能是最好的”,也不是问题的真正答案。 ('有什么好的方法吗?没有,但这里有一个难以想象的脆弱黑客。'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2013-04-04
  • 1970-01-01
  • 1970-01-01
  • 2019-12-08
  • 1970-01-01
相关资源
最近更新 更多