2010-06-09 13 views
7

Gibt es eine Möglichkeit, die Gtk-Bibliothek in C zu verwenden, um beispielsweise eine Gtk-Schaltfläche zu klonen und an anderer Stelle in der App zu packen. Ich weiß, dass du das gleiche Widget nicht zweimal packen kannst. Und dass dieser Code würde natürlich nicht funktionieren, aber zeigt, was passiert, wenn ich eine flache Kopie des Knopfes versuchen:Gibt es eine gute Möglichkeit, ein Gtk-Widget zu kopieren?

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

Es gibt Code umgeben, die eine vbox erstellt und packt es in einem Fenster und läuft gtk_main() . Dies wird in diesen harten führt Fehlermeldungen zu verstehen:

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

In der gleichen Richtung, wenn ich meine eigene GObject (nicht unbedingt ein GTK widget) zu schreiben, gibt es eine gute Möglichkeit, eine Kopie Konstruktor zu schreiben. Ich denke, es sollte eine Schnittstelle mit optionalen Hooks sein und hauptsächlich auf den Eigenschaften basieren und die Hierarchie der Klasse in irgendeiner Weise behandeln.

Ich würde dies tun wollen:

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

Wenn GtkButton eine theoretische kopierbar Schnittstelle nutzen könnten.

+0

Sie könnten eine GObject-Schnittstelle erstellen, die das "kopierfähige" Ding macht, indem Sie die Hooks und so weitergibt ... Ich würde es aber nicht schreiben wollen, es würde wahrscheinlich schwierig werden ... – Spudd86

Antwort

3

Ein Klon Throught Eigenschaften ist eine praktikable Lösung:

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

ein Widget Klonen allerdings nicht, dass trivial ist, aber der obige Ansatz ist verwendbar in den meisten Fällen (auf einem GtkButton sicher).

Es wäre mir egal, dass viele der Zustände nicht mit Eigenschaften exponiert sind (alle richtigen Widgets sollten vollständig durch Eigenschaften definiert sein, um mit GtkBuilder verwendbar zu sein), aber viele Eckenfälle machen ein robustes Klonen ziemlich schwierig (Schnittstellen und Container) die ersten zu sein, die mir in den Sinn kommen).

+0

Danke, das ist das Beste, was es für einen allgemeinen Kopierkonstruktor auf einem GObject geben könnte (und funktioniert für meine Bedürfnisse). – Jake

+1

Sie möchten auch nicht die Eigenschaften 'GtkWidget :: margin' und' GtkWidget :: expand' einstellen; Sie überschreiben andere Eigenschaften. – ptomato

+0

Auch wenn dies so gut funktionieren könnte, wie Sie es getestet haben, ist es nicht "lebensfähig" in dem Sinne, dass es eine sichere Empfehlung ist, den Menschen zu geben, aus den verschiedenen Gründen in der anderen Antwort und ihren Kommentaren. Es ist daher nicht "das Beste, was es für einen allgemeinen Kopierkonstruktor auf einem GObject geben könnte" und ist nicht die wirkliche Antwort auf die Frage. (Gibt es einen guten Weg? Nein, aber hier ist ein unvorstellbar zerbrechlicher Hack.) –

4

Ich glaube nicht. Soweit ich weiß, gibt es keine Garantie dafür, dass Widgets ihren gesamten Zustand in Eigenschaften behalten, auf die Sie von außen zugreifen können. Wenn ein Widget den Zustand "versteckt", indem es es nicht exportiert, gibt es keine Möglichkeit, es von außen zu kopieren.

Technisch gesehen können Widgets nur Felder in ihrem Kern enthalten struct, die Sie nicht von außerhalb der Implementierung sehen, so dass Sie nicht einmal die Bits mit einem dummen memcpy() kopieren können, es sei denn, Sie sind bereit, das Byte anzugeben -Zählen, indem Sie manuell zählen und ein Literal verwenden.

Das besagt, es ist auch durchaus möglich, dass genügend Widgets durch Eigenschaften, die eine Kopie immer noch funktionieren und möglicherweise nur geringfügige Störungen aufweisen, genügend Zustand verfügbar machen. Es wäre sicherlich ein ziemlich cooler Hack. Ich würde empfehlen, die GTK + -Entwickler direkt zu fragen, vielleicht auf der Mailingliste gtk-devel-list.

+0

Gute Antwort für seine Vorsicht, aber vielleicht nicht vorsichtig genug! Eine bitweise Kopie würde nicht funktionieren, mehr noch, aus dem gleichen Grund, dass man spezifische Kopierkonstruktoren z. C++: Wenn die Quelle Verweise auf andere Objekte enthält, würde eine bitweise Kopie zusätzliche Verweise auf diese erstellen, ohne ihre Referenzzahl zu erhöhen, was zu einer Verwendung nach Frees, Double-Frees und allen anderen Arten von Horror führt. Ich bin mir auch ziemlich sicher, dass die GTK + -Entwickler nicht daran interessiert sind, aus den Gründen, die wir hier gegeben haben, und auch nicht IMO. –

Verwandte Themen