2010-06-09 51 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

相關問題