1

複数の GTK ウィジェットにアクセスする必要があるコールバック関数があります。これを有効にするために、(グローバル変数を使用してアクセスを有効にするのではなく) コールバック関数への引数として、構造体にパッケージ化された関連する GTK ウィジェットへのポインターを送信しようとしています。適切な方法でデータを構造化するために、GTK ウィジェットへのポインターの構造へのポインターの構造を使用します。

私の問題は、コールバック関数で GTK ウィジェットを読み書きしようとすると、セグメンテーション違反が発生することです。どうすればこれを回避できますか? C と GTK の学習を始めたばかりなので、私のアプローチはまったく不適切である可能性があるため、コールバック関数から複数の GTK ウィジェットにアクセスする際の問題のより一般的な点についても指摘していただければ幸いです。

問題を解決しようとして、問題を示すコードを次のように煮詰めることができました。スピンボタンの値を変更すると、セグメンテーション違反が発生します。widget_change_value代わりに最後の行を実行させると、セグメンテーション違反も発生します。

/* Compile with gcc foo.c `pkg-config --cflags --libs gtk+-2.0` */
#include <gtk/gtk.h> /* Get e.g. via sudo apt-get install libgtk2.0-dev */

typedef struct {
    GtkWidget *widget;
} s_input;

typedef struct {
    s_input *input;
} s_data;

void widget_change_value(s_data *data) {
    /* Segfault when trying to read from data  */
    int number = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->input->widget));

    /* /\* Segfault when trying to write to data *\/ */
    /* gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->input->widget), (gdouble) 2.0); */
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    s_input input;
    s_data data = { &input };

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    input.widget = gtk_spin_button_new_with_range(0, 3, 1);
    gtk_container_add(GTK_CONTAINER(window), input.widget);
    g_signal_connect(GTK_OBJECT(input.widget), "value_changed", GTK_SIGNAL_FUNC(widget_change_value), (gpointer *) &data);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}
4

1 に答える 1

3

クラッシュは、コールバック関数のプロトタイプがすべて間違っているためです。

あなたが持っている:

void widget_change_value(s_data *data);

しかし、ドキュメントを見ると、value-changedシグナルハンドラのコールバックは次のように宣言されています。

void user_function(GtkSpinButton *spinbutton, gpointer user_data);

欠落しているウィジェット ポインター引数を追加する必要があります。

また:

  1. コールバックはstatic、それが含まれる C ファイルに対して非常にローカルであるため、 である必要があります。
  2. にキャストする必要はありませんgpointer
  3. 「へのポインター」ではなく、に変換したいポインター()を渡しているため、へのキャスト(gpointer *)は二重に間違っています。アスタリスクが間違っています。しかし、上で述べたように、キャスト全体は無意味であり、削除する必要があります。&datagpointergpointer
  4. より新しい GTK+ バージョンへの移植を検討してください。廃止されたものを使用しています (たとえば、 の代わりGTK_OBJECT()G_OBJECT()、のGTK_SIGNAL_FUNC()代わりに)。G_CALLBACK()
于 2012-10-31T11:57:32.083 に答える