2010-06-09 20 views
7

C'è un modo, usando la libreria Gtk in C, per clonare un pulsante Gtk (per esempio), e metterlo da qualche altra parte nell'app. So che non puoi impacchettare lo stesso widget due volte. E che questo codice, ovviamente, non avrebbe funzionato, ma mostra cosa succede quando si tenta una copia del pulsante:C'è un buon modo per copiare un widget 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)); 

è presente un codice che crea un vbox e confezioni in una finestra e corre gtk_main circostante() . Questo si tradurrà in questi difficili da capire i messaggi di errore:

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

Sulla stessa linea, se dovessi scrivere il mio GObject (non necessariamente un widget Gtk), c'è un buon modo per scrivere un costruttore di copia. Sto pensando che dovrebbe essere un'interfaccia con ganci opzionali e basata principalmente sulle proprietà, gestendo in qualche modo la gerarchia della classe.

avrei voluto fare questo:

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

Se GtkButton potrebbe usare un'interfaccia copiabile teorica.

+0

È possibile creare un'interfaccia GObject che faccia la cosa "copiabile" fornendo i ganci e tutto il resto ... Non vorrei scriverlo, ma probabilmente finirebbe per essere complicato ... – Spudd86

risposta

3

Un clone throught proprietà è una soluzione praticabile:

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

La clonazione di un widget non è così banale, però, ma l'approccio di cui sopra è utilizzabile nella maggior parte dei casi (su un GtkButton di sicuro).

Non mi interessa che molti degli stati non esposti con le proprietà (tutti i corretti widget dovrebbero essere completamente definiti dalle proprietà per essere utilizzabili con GtkBuilder) ma un sacco di casi d'angolo renderà abbastanza difficile una clonazione (interfacce e contenitori essendo i primi che mi vengono in mente).

+0

Grazie, questo è il meglio che ci possa essere per un costruttore di copia generico su un GObject (e funziona per le mie esigenze). – Jake

+1

Inoltre non si desidera impostare le proprietà 'GtkWidget :: margin' e' GtkWidget :: expand'; sovrascrivono altre proprietà. – ptomato

+0

Anche se questo potrebbe essere utile per tanto quanto l'hai provato, non è "praticabile" nel senso di essere un consiglio sicuro da fare alle persone, per le molteplici ragioni date nell'altra risposta e nei suoi commenti. Non è quindi "il meglio che ci possa essere per un costruttore di copia generico su un GObject" e non è la vera risposta alla domanda. ("È un buon modo? No, ma ecco un trucco inimmaginabilmente fragile.") –

4

Non credo. Per quanto ne so, non c'è alcuna garanzia che i widget mantengano tutto il loro stato in proprietà, a cui è possibile accedere dall'esterno. Se un widget "nasconde" lo stato non esportandolo, non è possibile copiarlo dall'esterno.

Tecnicamente, i widget può semplicemente includere campi a loro core struct che non si vede al di fuori della realizzazione, quindi non si può nemmeno copiare i bit utilizzando un muto memcpy(), a meno che non siete disposti a specificare il byte contiamo contando manualmente e usando un letterale.

Detto questo, è anche del tutto possibile che un numero sufficiente di widget esponga lo stato sufficiente attraverso le proprietà che una copia continuerà a funzionare e forse mostrerà solo piccoli inconvenienti. Sarebbe sicuramente un hack piuttosto interessante. Vorrei raccomandare direttamente agli sviluppatori principali di GTK +, magari sulla mailing list gtk-devel-list.

+0

Buona risposta per la sua cautela, ma forse non abbastanza prudente! Una copia bit a bit non funzionerebbe, a maggior ragione, per la stessa ragione per cui si devono scrivere specifici costruttori di copie in es. C++: perché se la fonte contiene riferimenti ad altri oggetti, una copia bit a bit creerebbe riferimenti aggiuntivi a questi, ma senza incrementare il loro conteggio di riferimento, portando a use-after-free, double-free e a tutti gli altri tipi di horror. Inoltre, sono abbastanza sicuro che gli sviluppatori di GTK + non sarebbero interessati a questo, per le ragioni che abbiamo fornito qui, e né IMO dovrebbero essere. –

Problemi correlati