2010-06-09 21 views
7

Có cách nào, bằng cách sử dụng thư viện Gtk trong C, để sao chép một nút Gtk (ví dụ), và gói nó ở một nơi khác trong ứng dụng. Tôi biết bạn không thể đóng gói cùng một widget hai lần. Và rằng mã này rõ ràng sẽ không làm việc, nhưng cho thấy những gì xảy ra khi tôi cố gắng một bản sao cạn của nút:Có cách nào tốt để sao chép tiện ích Gtk không?

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)); 

Có là mã mà tạo ra một vbox và gói nó trong một cửa sổ và chạy gtk_main xung quanh() . Điều này sẽ dẫn đến những khó khăn để hiểu các thông báo lỗi:

(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)) 

Dọc theo đường cùng, nếu tôi được viết GObject của riêng tôi (không nhất thiết là một widget Gtk), là có một cách tốt để viết một constructor sao chép. Im nghĩ rằng nó phải là một giao diện với các móc tùy chọn và dựa chủ yếu vào các thuộc tính, xử lý hệ thống phân cấp của lớp theo một cách nào đó.

Tôi muốn làm điều này:

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

Nếu GtkButton có thể sử dụng một giao diện copyable lý thuyết.

+0

Bạn có thể tạo giao diện GObject thực hiện điều 'có thể sao chép' bằng cách cung cấp móc và công cụ ... Tôi sẽ không muốn viết nó, mặc dù có lẽ gió sẽ trở nên khó khăn ... – Spudd86

Trả lời

3

Một clone Xuyên thuộc tính là một giải pháp khả thi:

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; 
} 

Nhân bản một widget mà không phải là tầm thường mặc dù, nhưng cách tiếp cận trên là có thể sử dụng trong hầu hết các trường hợp (trên GtkButton cho chắc chắn).

Tôi không quan tâm nhiều tiểu bang không được tiếp xúc với các thuộc tính (tất cả các tiện ích thích hợp phải được xác định đầy đủ bởi các thuộc tính có thể sử dụng được với GtkBuilder) nhưng rất nhiều trường hợp góc sẽ tạo ra một bản sao mạnh mẽ khá khó khăn (giao diện và vùng chứa) là những người đầu tiên đến với tâm trí của tôi).

+0

Cảm ơn, đây là điều tốt nhất có thể cho một nhà xây dựng bản sao chung trên GObject (và hoạt động cho các nhu cầu của tôi). – Jake

+1

Bạn cũng không muốn đặt thuộc tính 'GtkWidget :: margin' và' GtkWidget :: expand'; chúng ghi đè lên các thuộc tính khác. – ptomato

+0

Trong khi điều này có thể _seem_ để làm việc cho nhiều như bạn đã thử nghiệm nó, nó không phải là "khả thi" theo nghĩa là một đề nghị an toàn để làm cho mọi người, vì nhiều lý do được đưa ra trong câu trả lời khác và ý kiến ​​của nó. Do đó, không phải là "tốt nhất có thể cho một nhà xây dựng bản sao chung trên một GObject" và không phải là câu trả lời thực sự cho câu hỏi. (_'Là có một cách tốt? Không, nhưng đây là một hack dễ vỡ không thể tưởng tượng.'_) –

4

Tôi không nghĩ vậy. Theo tôi biết, không có gì đảm bảo rằng các tiện ích giữ tất cả trạng thái của chúng trong các thuộc tính, mà bạn có thể truy cập từ bên ngoài. Nếu một widget "ẩn" trạng thái bằng cách không xuất nó, không có cách nào bạn có thể sao chép nó từ bên ngoài. Về mặt kỹ thuật, các widget chỉ có thể bao gồm các trường trong lõi struct mà bạn không nhìn thấy từ bên ngoài triển khai, do đó bạn thậm chí không thể sao chép các bit bằng cách sử dụng số memcpy() câm, trừ khi bạn sẵn sàng chỉ định byte -count bằng cách đếm theo cách thủ công và sử dụng chữ.

Điều đó đang được nói, cũng hoàn toàn có thể là đủ tiện ích hiển thị đủ trạng thái thông qua các thuộc tính mà bản sao vẫn hoạt động và có lẽ chỉ hiển thị các lỗi nhỏ. Nó chắc chắn sẽ là một hack khá hay. Tôi khuyên bạn nên hỏi các nhà phát triển GTK + lõi trực tiếp, có lẽ trên danh sách gửi thư gtk-devel-list.

+0

Câu trả lời hay cho sự thận trọng của nó, nhưng có lẽ không đủ thận trọng! Một bản sao bitwise sẽ không hoạt động, nhiều hơn như vậy, vì lý do tương tự mà người ta phải viết các nhà xây dựng bản sao cụ thể trong ví dụ: C++: bởi vì nếu nguồn chứa tham chiếu đến các đối tượng khác, một bản sao bitwise sẽ tạo ra các tham chiếu bổ sung cho nhưng không tăng số lượng tham chiếu của chúng, dẫn đến sử dụng sau khi giải phóng, giải phóng đôi và tất cả các cách kinh dị khác. Ngoài ra, tôi khá chắc chắn rằng các nhà phát triển GTK + sẽ không quan tâm đến điều này, vì những lý do chúng tôi đã đưa ra ở đây, và cũng không phải là IMO. –

Các vấn đề liên quan