2017-11-08 13 views
1

GtkWidgetの配列に格納されているラベルのフォント色を変更するコールバックを作成する必要があります。GtkWidgetの配列の要素をコールバックで変更する方法

GtkWidget *cells[CELLS]; 
for (int i=0; i<CELLS; i++) { 
    cells[i] = gtk_label_new("██"); 
} 
ボタンに

接続されたコールバック:

g_signal_connect(
    G_OBJECT(button), 
    "clicked", 
    G_CALLBACK(encode), 
    make_data(plaintext, key, cells) 
); 

make_data()

コードでは、現在の状態は、私の配列は、次のようになりますインターフェイスを初期化する関数では、ここでhttps://github.com/dustynine/colta-gtk/blob/struct/src/main.c

ありますコールバックの引数を持つ構造体を返す関数です:

struct passed_widgets { 
    GtkWidget *plaintext; 
    GtkWidget *key; 
    GtkWidget **cls; 
}; 

gpointer make_data(GtkWidget *text, GtkWidget *key, GtkWidget *cells[CELLS]) { 
    static struct passed_widgets pw; 
    pw.plaintext = text; 
    pw.key = key; 
    pw.cls = cells; 
    return (gpointer) &pw; 
} 

そして0コールバック自体の内部I持っているこの:

static void encode(GtkButton *button, gpointer *data) { 
    struct passed_widgets *pw; 
    GdkColor color; 
    pw = (struct passed_widgets *) data; 

    gdk_color_parse("#07d9d9", &color); 
    gtk_widget_modify_fg(GTK_WIDGET(pw -> cls[0]), GTK_STATE_NORMAL, &color); 
} 

コンパイラが、私は実際にボタンを押すとG​​tkのは、この報告(色関連のものが推奨されていません警告は別として)文句はありません。

(colta-gtk:3993): GLib-GObject-WARNING **: invalid uninstantiatable type 'GInterface' in cast to 'GtkWidget' 
(colta-gtk:3993): Gtk-CRITICAL **: gtk_widget_modify_fg: assertion 'GTK_IS_WIDGET (widget)' failed 

Iは少しのためにGDBの中を拾い、explore pw -> cls[0]に従って:

'pw -> cls[0]' is a pointer to a value of type 'GtkWidget' 

この作業を意図どおりに行うにはどうすればよいですか?私は間違って構造体に配列を割り当てるか(これはプログラムが働く唯一の方法です)、またはコールバックの終わりにそれを変更しようとしているときに間違ってアクセスしている疑いがあります。


EDIT: liberforceが示唆したように、私はプログラムを書き直しました。

struct template { 
    GtkWidget *window; 
    ... 
    GtkWidget *plaintext; 
    GtkWidget *cells[CELLS]; 
}; 

今、私はちょうど私がコールバックするguiとしてインスタンスこの構造体の渡し:

g_signal_connect(
    G_OBJECT(gui.button), 
    "clicked", 
    G_CALLBACK(encode), 
    &gui 
); 

をしかし、私はエンコード()関数内で動作するように何かを得ることができない私のGUIのための構造体を作成しましたもう一度:

static void encode(GtkButton *button, gpointer data) { 
    gchar *plaintext; 
    struct template *pw; 

    pw = (struct template *) data; 

    plaintext = gtk_entry_get_text(GTK_ENTRY(pw -> plaintext)); 
    printf(" plaintext contents: %s\n", plaintext); 

もう一度私は何が間違っているのか分かりません。コンパイラは型が一致GDBによると、何の警告を与えていないが、私はプログラムを実行して、コールバックを使用する場合には、その私を与える:次のように

(colta-gtk:21589): Gtk-CRITICAL **: gtk_entry_get_buffer: assertion 'GTK_IS_ENTRY (entry)' failed 

(colta-gtk:21589): Gtk-CRITICAL **: gtk_entry_buffer_get_text: assertion 'GTK_IS_ENTRY_BUFFER (buffer)' failed 

アドレスは次のとおりです。

gui.plaintext address: 0x55babcfc6290 
gui address: 0x7ffd13fe8a88 
&gui address: 0x7ffd13fe8910 
data address: 0x7ffd13fe8910 
pw address: 0x7ffd13fe8910 
*pw address: 0x7ffd13fe8a88 
pw -> plaintext address: (nil) 

*pw -> plaintextセグメンテーションエラーが発生する

答えて

0

私はそれを得たと思う。

static void activate(GtkApplication* app, gpointer user_data) { 
    static struct template gui; 

    gui.plaintext = gtk_entry_new(); 
    printf("gui.plaintext address: %p\n", gui.plaintext); 

    g_signal_connect(
     G_OBJECT(gui.button), 
     "clicked", 
     G_CALLBACK(encode), 
     &gui 
    ); 

とエンコードコールバックで私はこれを持っている:私はこれを行うアプリの信号を「活性化」に呼ばれるコールバックに続いてmain()

struct template { 
    GtkWidget *window; 
    ... 
    GtkWidget *plaintext; 
    GtkWidget *cells[CELLS]; 
}; 

外の構造体のプロトタイプを作成します

static void encode(GtkButton *button, gpointer data) { 
    gchar *plaintext; 
    struct template *pw; 

    pw = (struct template *) data; 

    plaintext = gtk_entry_get_text(GTK_ENTRY(pw -> plaintext)); 
    printf(" plaintext contents: %s\n", plaintext); 

    GdkColor color; 
    gdk_color_parse("#ff0000", &color); 
    gtk_widget_modify_fg(GTK_WIDGET(pw -> cells[0]), GTK_STATE_NORMAL, 
    &color); 
} 

これですべてが意図どおりに機能します。基本的にはactivateコールバックにstaticをという宣言に追加して問題を修正しました。私は将来の参考のためgithub上のファイルの作業用バージョンへのリンクを残しておきます。正しい方向に私を指差してくれてありがとう。

+0

あなたがGtkApplicationを使っていたことはわかりませんでした。 'activate'シグナルに接続するときにスタックの割り当ては、あなたの構造体のアドレスを' user_data'として渡すと、メインで動作します。あるいは、静的と宣言することもできますが、コールバックハンドラでは行いません。ファイルの一番上で行います。ファイルにグローバルなオブジェクトが表示されるようにします。 'g_new'でヒープ上に構造体を作成することもできます。重要なことは、あなたのgui構造体はアプリケーションと同じ寿命を持たなければならないということです。 – liberforce

+0

これは、コールバック内のスタックに構造体を宣言すると、コールバックを終了するときに構造体が破棄されることを意味します。 – liberforce

+0

ところで、実際のビルドシステムに切り替えることもしよう。たとえば、ビルドスクリプトは私のためにはうまくいきませんでした。なぜなら私は 'bash'を持っているが' sh'は持っていないからです。 Mesonビルドシステムは、GTK/GNOMEプロジェクト用に推奨されるビルドシステムです:http://mesonbuild.com/。例えば、Mesonは '-Wall'を有効にして、合理的な警告セットを有効にしました(そして、それを常に最低限使用しなければなりません)。現代のGTK +/Cアプリケーションを書く上でベストプラクティスに追いつこうとしているhttps://github.com/liberforce/metrognomeで私のレポを見たいかもしれません。 – liberforce

0

エンコードのプロトタイプが間違っています。それはgpointer dataでなく、gpointer *dataでなければなりません。 gpointerはすでにvoid *のtypedefです。

また、あなたのmake_data関数は、あなたの構造体の引数へのポインタをとり、それを埋めてください。静的構造体を使用しないでください。コードを再利用しにくくするためです。

通常、私はちょうどそのg_signal_connectの最後の引数として、そのスタックに割り当てられた構造体(またはそのサブ要素)のアドレスを渡し、それを埋める、私のGUIを表す私のmainstructを作成します。

さらにポインタはgpointerに明示的にキャストする必要はありません。すべてのポインタを暗黙的にgpointerにキャストできるためです。

+0

提案したように、すべてのGUIを構造体に入れましたが、このバリアントをまったく動作させることができませんでした。 OPに詳細を追加しました – dustynine

+0

これらのアサーションは、無効なポインタを渡すために発生します。有効なポインタではないか、有効なウィジェットですが、期待しているタイプのウィジェットではありません。 'pw-> plainext'はGtkEntryであると予想されます。私はあなたがそれを使用する方法に間違って何も見ないので、バグはあなたが構造体を初期化する方法にあるかもしれません。 – liberforce

+0

また、 'gtk_entry_get_text'を呼び出して、' GtkEntry'の中のテキストを取得してください。 – liberforce

関連する問題