GTK+ でプログラミング:基本形

とりあえず、GTK+ で何かを作るときに基本形となるものをば。これを拡張していけば大抵のものは作れるかと。w

ちなみに、GTK+ の関数仕様については、DevHelp というマニュアルを使って調べるのが便利。メニュー Application → Programming の中に入っていると思う。入ってなかったらアプリケーション追加でインストールしておく。

まずプログラム全体はこんな感じ。

  1 #include <gtk/gtk.h>
  2 
  3 static void destroy(GtkWidget *window, gpointer data)
  4 {
  5     /*  メインループを終了  */
  6     gtk_main_quit();
  7 }
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     GtkWidget *window, *label;
 12 
 13     /*  GTK+ の初期化  */
 14     gtk_init(&argc, &argv);
 15 
 16     /*  ウィンドウ(GtkWindow) の作成  */
 17     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 18 
 19     /*  ウィンドウの初期設定  */
 20     gtk_window_set_title(GTK_WINDOW(window), "Hello");  //  title
 21     gtk_widget_set_size_request(window, 200, 100);      //  window size
 22 
 23     /*  ウィンドウが消去されたときのコールバック関数を設定  */
 24     g_signal_connect(G_OBJECT(window), "destroy",
 25                      G_CALLBACK(destroy), NULL);
 26 
 27     /*  ラベル(GtkLabel) の作成  */
 28     label = gtk_label_new("Hello, Mirin!");
 29 
 30     /*  ラベルをウィンドウに追加  */
 31     gtk_container_add(GTK_CONTAINER(window), label);
 32 
 33     /*  ウィンドウを表示  */
 34     gtk_widget_show_all(window);
 35 
 36     /*  メインループ  */
 37     gtk_main();
 38 
 39     return 0;
 40 }


以下、それぞれの箇所について解説。

  1 #include <gtk/gtk.h>

GTK+ で開発を行うときに最低限必要なヘッダファイルはこれ。

  9 int main(int argc, char *argv[])
 10 {
 11     GtkWidget *window, *label;

ウィンドウやラベルなど、ウィジェットを格納するための変数を宣言。
ここでは2つの変数を GtkWidget *型で宣言しているが、実際には window には GtkWindow 型のオブジェクトが、また label には GtkLabel 型のオブジェクトが格納される。この2つの型は GtkWidget を継承したものであり、宣言時にはGtkWidget 型を使うとよい。

 13     /*  GTK+ の初期化  */
 14     gtk_init(&argc, &argv);

GTK+を初期化する。
関数 gtk_init() は、GTK+ 関連のすべての操作を行う前に呼び出す必要がある。
引数は main 関数で渡されたものを何も考えずそのままアドレス渡しすればよい。

 16     /*  ウィンドウ(GtkWindow) の作成  */
 17     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

まずウィンドウオブジェクトを作成する。
引数で GTK_WINDOW_TOPLEVEL と指定しているが、これはウィンドウのタイプ。ここで指定できるのは、以下のいずれか。(GtkWindowType で定義されている)

  • GTK_WINDOW_TOPLEVEL

いわゆる「普通のウィンドウ」。WindowManagerが提供するいろいろな機能の恩恵をうけられる(ウィンドウのリサイズや、ショートカットキーの使用など)。特別な理由がない限りはこちらを使う。

  • GTK_WINDOW_POPUP

特殊な場合にのみ使われる。これを指定したウィンドウは、WindowManager の提供する一切の機能が使えなくなる。
用途としては、ウィンドウの上に表示されるメニューやツールチップなどがある。

 19     /*  ウィンドウの設定  */
 20     gtk_window_set_title(GTK_WINDOW(window), "Hello");  //  title
 21     gtk_widget_set_size_request(window, 200, 100);      //  window size

ウィンドウに対していくつかの設定を行う。
まず、gtk_window_set_title() を使って、ウィンドウのタイトルを設定している。
ここで問題になるのが、第1引数の指定方法。関数仕様によると、第1引数では GtkWindow * を指定することになっている。しかし window という変数は GtkWidget * 型で宣言されている。
したがって、この window はキャストしてあげる必要がある。GtkWidget * 型を GtkWindow *型に変換するには、GTK_WINDOW() 関数を使う。
ちなみに GTK+でのプログラミングでは、この手のキャストは頻繁に使われる。他にも GTK_CONTAINER などいろいろあるので、第一引数で指定すべき型に応じて使い分ける。

次に、gtk_widget_set_size_request() で、そのウィンドウに対してサイズを設定している。第1引数は GtkWidget *型なので、ここではキャストの必要はない。

 23     /*  ウィンドウが消去されたときのコールバック関数を設定  */
 24     g_signal_connect(G_OBJECT(window), "destroy",
 25                      G_CALLBACK(destroy), NULL);

ウィンドウに対してなんらかのアクションが行われたときのコールバック関数を設定する。ここでは、ウィンドウ右上の×ボタンが押されるなど、ウィンドウを閉じる操作が行われたときに、destroy というコールバック関数を呼び出すように指定している。
なお、第4引数は、コールバック関数に渡す引数。ここでは NULL を指定しているため、何も渡されない。


次に、文字を表示するためのラベルオブジェクトを作成する。

 27     /*  ラベル(GtkLabel) の作成  */
 28     label = gtk_label_new("Hello, Mirin!");

引数に、ラベル上に表示させたい文字をそのまま指定する。

 30     /*  ラベルをウィンドウに追加  */
 31     gtk_container_add(GTK_CONTAINER(window), label);

そしてこのラベルを、先ほど生成したウィンドウに貼り付ける。

 33     /*  ウィンドウを表示  */
 34     gtk_widget_show_all(window);

ウィンドウの準備がすべて整ったので、ここで表示を行う。

 36     /*  メインループ  */
 37     gtk_main();

そしてメインループへと入る。
gtk_main() によるメインループが続いている間は、ウィンドウに対していろいろな操作を行える。このループを抜けるのは、次に出てくる gtk_main_quit() が呼ばれた時。


24行目で設定したコールバック関数 destroy() は、ウィンドウを閉じようとしたときに呼ばれる。

  3 static void destroy(GtkWidget *window, gpointer data)
  4 {
  5     /*  メインループを終了  */
  6     gtk_main_quit();
  7 }

gtk_main_quit() がここで呼ばれている。つまり、ウィンドウ右上の×印が押されるなどしてウィンドウが閉じられ
るときに、gtk_main() のループが終了する。


以上の内容を hello.c として保存してコンパイル

gcc -Wall -o hello hello.c `pkg-config --cflags --libs gtk+-2.0`


そして実行。

> ./hello

ウィンドウが現れ、その中に文字列が表示される。
リサイズや移動も自由にできる。右上の×印で終了。


参考: Foundations of GTK+ Development