コールバック関数の共有


今までは、1つのボタンに1つの役割を持たせて来た。 今回は、2つのボタンに同じ処理をさせてみる。

#include <gtk/gtk.h>

static void cb_button(GtkWidget *widget, gpointer user_data)
{
  static gint count = 0;
  gchar buf[64];
  if( count < 1 ){
    sprintf( buf, "%d time clicked.", ++count);
  }
  else {
    sprintf( buf, "%d times clicked.", ++count);
  }
  gtk_button_set_label(GTK_BUTTON(widget), buf);
}

int main(int argc, char** argv)
{
  GtkWidget *window;
  GtkWidget *hbox;
  GtkWidget *button1;
  GtkWidget *button2;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Count");
  gtk_widget_set_size_request(window, 500, 50);
  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_container_add(GTK_CONTAINER(window), hbox);

  button1 = gtk_button_new_with_label("0 time clicked.");
  gtk_box_pack_start(GTK_BOX(hbox), button1, TRUE, TRUE, 0);
  g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(cb_button), NULL);

  button2 = gtk_button_new_with_label("Click here");
  gtk_box_pack_start(GTK_BOX(hbox), button2, TRUE, TRUE, 0);
  //button1クリック時と同じ関数を呼び出す
  g_signal_connect_swapped(G_OBJECT(button2), "clicked", G_CALLBACK(cb_button), (gpointer)button1);

  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

右のボタンをクリックすると、左のボタン・ラベルがカウント表示される。

左のボタンをクリックしても、同様に左のボタン・ラベルがカウント表示される。

g_signal_connect_swappedの第1引数(button2)には、 第4引数(button1)で指定したウィジェットが渡される。

これを用いれば、複数ボタンのクリックで、同一関数の処理を行う事ができる。


コールバック関数の解除


ボタンのクリックにより関数処理を行なって来たが、 プログラム実行中にその役目を終えさせる事もできる

#include <gtk/gtk.h>

static void cb_button(GtkWidget *widget, gpointer user_data)
{
  //コールバック関数に設定されていれば実行される
  g_print( "Callback function is called.\n" );
}

static void disconnect_handler(GtkWidget *widget, gpointer user_data)
{
  GtkWidget *button;
  gulong handle;

  button = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "button1"));
  handle = (gulong)g_object_get_data(G_OBJECT(widget), "handle");

  //コールバック関数が解除されていない場合
  if(g_signal_handler_is_connected(button, handle)){
    //buttonウィジェットをコールバック関数の指定ID(handle)から解除
    g_signal_handler_disconnect(button, handle);
    g_print( "Callback function is disconnecter.\n" );
    return;
  }
  //コールバック関数が解除されている場合
  else{
    //すでに解除されている事を表示
    g_print( "Callback function is already disconnecter.\n" );
  }
}

int main(int argc, char** argv)
{
  GtkWidget *window;
  GtkWidget *hbox;
  GtkWidget *button1;
  GtkWidget *button2;
  gulong handle;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Disconnect");
  gtk_widget_set_size_request(window, 500, 50);
  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_container_add(GTK_CONTAINER(window), hbox);

  button1 = gtk_button_new_with_label("button1");
  gtk_box_pack_start(GTK_BOX(hbox), button1, TRUE, TRUE, 0);
  //コールバック関数のIDを指定
  handle = g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(cb_button), NULL);

  button2 = gtk_button_new_with_label("Disconnect button1 callbacks.");
  //GObject型の変数を関連付ける(g_object_set_data)
  g_object_set_data(G_OBJECT(button2), "button1", (gpointer)button1);
  g_object_set_data(G_OBJECT(button2), "handle", (gpointer)handle);
  gtk_box_pack_start(GTK_BOX(hbox), button2, TRUE, TRUE, 0);
  g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(disconnect_handler), NULL);

  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

「button1」ボタンをクリックすると、登録されているコールバック関数が処理される。

「Disconnect button1 callbacks.」ボタンをクリックする事で、 button1のコールバック関数を解除する。 再び「button1」ボタンをクリックしても、処理されなくなる。

サンプルではbutton1の登録を解除させた事で、解除ボタンの役目を終えたメッセージを表示させている。

サンプルでは、g_object_set_dataを用いている。

第1引数:オブジェクト、第2引数:関連付ける変数識別の文字列、第3引数:関連付ける変数、である。

また、関連付けた変数を取得するg_object_get_dataも有る。

第1引数:オブジェクト、第2引数:関連付ける変数識別の文字列、となる

コールバック関数の解除にはg_signal_handler_disconnectを用いた。

解除されているかを確認するのに、g_signal_handler_is_connectedが使える。

第1引数:コールバック関数を登録したオブジェクト、第2引数:コールバック関数IDである。


プログラム終了前の確認


プログラムを閉じる時に、本当に終了してよいか、確認するダイアログを表示させる。

#include <gtk/gtk.h>

static gboolean cb_delete(GtkWidget *widget, gpointer user_data)
{
  GtkWidget *dialog;
  gint result;

  //YESかNOを選択するダイアログを表示
  dialog = gtk_message_dialog_new(GTK_WINDOW(widget), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Confirm are you sure you want to quit.");
  result = gtk_dialog_run(GTK_DIALOG(dialog));
  gtk_widget_destroy(dialog);
  //YESを選択した場合
  if(result == GTK_RESPONSE_YES){
    //destroyシグナルが発生(指定したcb_destroy関数へ)
    return FALSE;
  }
  //NOを選択した場合
  else{
    //何も発生しない
    return TRUE;
  }
}

static void cb_destroy(GtkWidget *widget, gpointer user_data)
{
  //プログラムを終了
  gtk_main_quit();
}

int main(int argc, char** argv)
{
  GtkWidget *window;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Delete");
  gtk_widget_set_size_request(window, 250, 50);
  //ウィンドウを閉じる際に、delete-eventシグナルを発生させる
  g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(cb_delete), NULL);
  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(cb_destroy), NULL);

  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

ウィンドウを閉じる前に確認。

「はい(Y)」をクリックしてプログラムを終了。


前章  | 目次 |  次章



トップ



/