2010-06-09 66 views
7

有没有办法,使用C中的Gtk库来克隆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)); 

有围绕它创建了一个纵向盒和包装它在一个窗口中,并运行进入主循环代码() 。这将导致这些难以理解的错误消息:

(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上可以使用的理论可复制的接口。

+0

你可以创建一个GObject接口,通过提供钩子和东西来完成'可复制'的事情...我不想写它,但它可能会变得棘手... – Spudd86 2010-06-16 20:46:04

回答

3

throught性克隆是一个可行的解决方案:

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一起使用),但是很多角落案例会使得强大的克隆非常困难(接口和容器是我想到的第一批)。

+0

谢谢,这是GObject上的一般拷贝构造函数的最佳选择(并且适合我的需求)。 – Jake 2010-06-16 05:22:06

+1

您也不想设置'GtkWidget :: margin'和'GtkWidget :: expand'属性;他们覆盖其他属性。 – ptomato 2014-09-19 08:43:26

+0

虽然这可能会像您测试过的那样起作用,但从其他回答及其评论中给出的多种原因来看,它并不是“可行”的,因为它是向人们提供的安全建议。因此,它不是“GObject上的一般拷贝构造函数最好的”,也不是问题的真正答案。 (_有没有好的方法?不,但是这里有一个难以想象的脆弱的黑客。') – 2017-07-18 10:31:45

4

我不这么认为。据我所知,不能保证小部件将所有状态保留在属性中,以便从外部访问。如果一个小部件通过不导出而“隐藏”状态,那么您无法从外部复制它。

从技术上讲,窗口小部件可以在其核心struct中包含字段,但是在实现之外没有看到,所以甚至不能使用哑元memcpy()复制这些位,除非您愿意指定字节 - 通过手动计数和使用文字计数。这就是说,也有可能是足够的小部件通过属性暴露足够的状态,副本仍然可以发挥作用,并且可能只会表现出轻微的故障。这肯定是一个非常酷的黑客。我建议直接询问核心GTK +开发人员,也许在gtk-devel-list邮件列表上。

+0

好的答案它的谨慎,但也许不够谨慎!逐位复制不起作用,更为重要的是,出于同样的原因,必须在例如C++:因为如果源保存对其他对象的引用,按位副本将创建对这些引用的附加引用,但不增加引用计数,导致释放后使用,双释放和所有其他方式的恐怖。另外,我非常确定GTK +开发人员不会对此感兴趣,因为我们在这里给出的理由,也不应该是IMO。 – 2017-07-18 10:29:53

相关问题