Is there a good way to copy a Gtk widget?
Is there a way, using the Gtk library in C, to clone a Gtk button (for instance), and pack it somewhere else in the app. I know you can't pack the same widget twice. And that this code obviously wouldn't work, but shows what happens when I attempt a shallow copy of the button:
GtkButton *a = g_object_new(GTK_TYPE_BUTTON, "开发者_Go百科label", "o_0", NULL);
GtkButton *b = g_memdup(a, sizeof *a);
gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(b));
There is surrounding code which creates a vbox and packs it in a window and runs gtk_main(). This will result in these hard to understand error messages:
(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))
Along the same lines, if I were to write my own GObject (not necessarily a Gtk widget), is there a good way to write a copy constructor. Im thinking it should be an interface with optional hooks and based mostly on the properties, handling the class's hierarchy in some way.
I'd want to do this:
GtkButton *b = copyable_copy(COPYABLE(a));
If GtkButton could use a theoretical copyable interface.
I don't think so. As far as I know, there's no guarantee that widgets keep all their state in properties, that you can access from the outside. If a widget "hides" state by not exporting it, there's no way you can copy it from the outside.
Technically, widgets can just include fields in their core struct
that you don't see from outside of the implementation, so you can't even copy the bits using a dumb memcpy()
, unless you're willing to specify the byte-count by counting manually and using a literal.
That being said, it's also quite possible that enough widgets expose enough state through properties that a copy would still function, and perhaps only exhibit minor glitches. It would certainly be a pretty cool hack. I would recommend asking the core GTK+ developers directly, perhaps on the gtk-devel-list mailing list.
A clone throught properties is a viable solution:
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(¶ms[n_params].value, specs[n]->value_type);
g_object_get_property(src, specs[n]->name, ¶ms[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;
}
Cloning a widget is not that trivial though, but the above approach is usable in most cases (on a GtkButton
for sure).
I'd not care that much of states not exposed with properties (all proper widgets should be fully defined by properties to be usable with GtkBuilder
) but a lot of corner cases will make a robust cloning quite difficult (interfaces and containers being the first ones that come to my mind).
精彩评论