* GTKアプリケーション [#j1af719f]

GTK を用いて、GUI アプリケーションを作成しましょう。今回利用するのは、GTK1.2 です。C言語のライブラリなので、クラスを模した記述をします。

** 基本ソース例 [#he8c0b8c]
以下のソースは、ウィンドウ上にラベルとボタンを1つずつ配置した GUI アプリケーションです。ボタンを押すとイベントが発生して、ラベルの内容を書き換えます。 

 #include <gtk/gtk.h>
 #include <stdio.h>
 
 /*************************************************
  * ボタンが押されたときのイベントハンドラ
  ************************************************/
 void btn_click1(GtkWidget *wig,gpointer p) {
 void btn_click(GtkWidget *wig,gpointer p) {
     // ラベルに文字列を設定する
     gtk_label_set_text(label_mes, "いてっ!");
 }
 
 /*************************************************
  * メイン関数
  ************************************************/
 int main(int argc, char* argv[])
 {
     GtkWidget *window;          // ウィンドウ
     GtkWidget *label_mes;       // ラベル
     GtkWidget *button;          // ボタン
 
     // 適切なロケール情報が設定される(日本語文字列を使う場合は必須)
     gtk_set_locale();
     // GTK の初期化(必須)
     gtk_init(&argc, &argv);
 
     // ウィンドウを作成する
     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     // ウィンドウで「×ボタン」が押されたときのシグナルを登録する
     gtk_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
     // ウィンドウを表示する
     gtk_widget_show(window);
 
     // ボタンを、「叩く」というラベルを付けて作成する
     button1 = gtk_button_new_with_label("叩く");
     button = gtk_button_new_with_label("叩く");
     // ボタンが押されたときのシグナルを登録する
     gtk_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(btn_click1),NULL);
     gtk_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(btn_click),NULL);
     // ボタンをウィンドウ上に載せる
     gtk_container_add(GTK_CONTAINER(window),button1);
     gtk_container_add(GTK_CONTAINER(window),button);
     // ボタンを表示する
     gtk_widget_show(button1);
     gtk_widget_show(button);
 
     // ラベルを、「空っぽ」という初期文字列を付けて作成する
     label_mes = gtk_label_new("〜♪");
     // ラベルをウィンドウ上に載せる
     gtk_container_add(GTK_CONTAINER(window),label_mes);
     // ラベルを表示する
     gtk_widget_show(label_mes);
 
     // GTK メインループに入る(イベント待受け状態へ移行する)
     gtk_main();
 
     return 0;
 }

上記のソースが、GTK による GUI プログラミングの基本的な形になります。あとは、必要に応じてコンポーネントやイベントの追加を行なってください。

** ビルド方法 [#f9c1b772]
ビルドは下記のように行ないます。ヘッダファイルとライブラリは、gtk-config コマンドにより、自動的に設定されます。

 gcc -o gtk_test gtk_test.c `gtk-config --cflags` `gtk-config --libs`

** 各コンポーネントのレイアウト [#y59bc630]
各コンポーネント(ボタン、ラベルなど)は、垂直ボックスと水平ボックスを組み合わせてレイアウトします。

|垂直ボックス|コンポーネントを上から順番に、縦方向へレイアウトする|
|水平ボックス|コンポーネントを上から順番に、横方向へレイアウトする|

** 応用ソース例 [#vc2f27f1]
応用というわけではありませんが、先に紹介した基本ソース例にもう少し多くの要素を加えています。

 #include <gtk/gtk.h>
 #include <stdio.h>
 
 // イベント内など関数外で利用する変数
 // (別ファイルで使う場合は、extern 宣言を追加する)
 GtkWidget *label_mes;       // ラベル
 GtkWidget *textfield;       // 1行テキストフィールド
 
 /*************************************************
  * ボタン 1 が押されたときのイベントハンドラ
  ************************************************/
 void btn_click1(GtkWidget *wig,gpointer p) {
     // 1行テキストフィールドに設定されている文字列を取得する
     gchar* text = gtk_entry_get_text(textfield);
     // ラベルに文字列を設定する
     gtk_label_set_text(label_mes, text);
 }
 
 /*************************************************
  * ボタン 2 が押されたときのイベントハンドラ
  ************************************************/
 void btn_click2(GtkWidget *wig,gpointer p) {
     // ラベルに空文字列を設定する
     gtk_label_set_text(label_mes, "");
 }
 
 /*************************************************
  * タイマーイベントのハンドラ
  ************************************************/
 void timer_event(GtkWidget *wig,gpointer p) {
     // 標準出力する
     printf("Timer Call");
 }
 
 
 void* windowThread(void* param);
 
 /*************************************************
  * メイン関数
  ************************************************/
 int main(int argc, char* argv[])
 {
     pthread_t tid;
 
     // 適切なロケール情報が設定される(日本語文字列を使う場合は必須)
     gtk_set_locale();
     // GTK の初期化(必須)
     gtk_init(&argc, &argv);
 
     // 新規にスレッドを生成し、そこで GUI 画面を作成する。
     // もちろんメインスレッド内でも構わないが、その場合バックグラウンドの処理はできない
     pthread_create(&tid,NULL,windowThread,NULL);
     // GUI 画面用のスレッドが終了するまで、待ち受ける
     pthread_join(tid,NULL);
 
     return 0;
 }
 
 /*************************************************
  * GUI 画面生成する関数(スレッド登録用)
  ************************************************/
 void* windowThread(void* param) {
     GtkWidget *window;          // ウィンドウ
     GtkWidget *vbox;            // 垂直ボックス
     GtkWidget *hbox;            // 水平ボックス
     GtkWidget *button1;         // ボタン 1
     GtkWidget *button2;         // ボタン 2
     GtkStyle *label_style;      // スタイル
 
     // スタイルを作成する
     label_style = gtk_style_new();
     // スタイルのフォントを、所定のフォントセットとする。
     // フォントセットとは、フォントをカンマで繋いだものである
     label_style->font = 
     gdk_fontset_load("-*-marumoji-*-*-*--*-*-*-*-*-*-jisx0201.1976-0,-*-marumoji-*-*-*--*-*-*-*-*-*-jisx0208.1990-0");
 
     // ウィンドウを作成する
     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     // ウィンドウで「×ボタン」が押されたときのシグナルを登録する
     gtk_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
     // ウィンドウを表示する
     gtk_widget_show(window);
 
     // 垂直ボックスを、要素間隔 5 ピクセルで作成する
     vbox = gtk_vbox_new(FALSE, 5);
     // 垂直ボックスをウィンドウ上に載せる
     gtk_container_add(GTK_CONTAINER(window), vbox);
     // 垂直ボックスを表示する
     gtk_widget_show(vbox);
 
     // テキストフィールドを作成する
     textfield = gtk_entry_new();
     // テキストフィールドを垂直ボックス上に載せる
     gtk_container_add(GTK_CONTAINER(vbox),textfield);
     // テキストフィールドを表示する
     gtk_widget_show(textfield);
 
     // 水平ボックスを、要素間隔 5 ピクセルで作成する
     hbox = gtk_hbox_new(FALSE, 5);
     // 水平ボックスをウィンドウ上に載せる
     gtk_container_add(GTK_CONTAINER(vbox), hbox);
     // 水平ボックスを表示する
     gtk_widget_show(hbox);
 
     // ボタン 1 を、「反映」というラベルを付けて作成する
     button1 = gtk_button_new_with_label("反映");
     // ボタン 1 が押されたときのシグナルを登録する
     gtk_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(btn_click1),NULL);
     // ボタン 1 を水平ボックス上に載せる
     gtk_container_add(GTK_CONTAINER(hbox),button1);
     // ボタン 1 を表示する
     gtk_widget_show(button1);
 
     // ボタン 2 を、「消去」というラベルを付けて作成する
     button2 = gtk_button_new_with_label("消去");
     // ボタン 2 が押されたときのシグナルを登録する
     gtk_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(btn_click2),NULL);
     // ボタン 2 を水平ボックス上に載せる
     gtk_container_add(GTK_CONTAINER(hbox),button2);
     // ボタン 2 を表示する
     gtk_widget_show(button2);
 
     // ラベルを、「空っぽ」という初期文字列を付けて作成する
     label_mes = gtk_label_new("空っぽ");
     // ラベルに対して、スタイルを適用する
     gtk_widget_set_style(label_mes, label_style);
     // ラベルに適用されたスタイルを反映させる
     gtk_widget_ensure_style(label_mes);
     // ラベルを垂直ボックス上に載せる
     gtk_container_add(GTK_CONTAINER(vbox),label_mes);
     // ラベルを表示する
     gtk_widget_show(label_mes);
 
     // タイムアウトイベントを登録する(周期的に呼ばれるイベント)
     gtk_timeout_add(1000, (GtkFunction)timer_event, NULL);
 
     // GTK メインループに入る(イベント待受け状態へ移行する)
     gtk_main();
 
     return NULL;
 }

** FAQ [#of24472a]
:日本語がまったく表示されない|gtk_set_locale() 関数は、ちゃんと呼び出していますか?
:日本語が化けて表示される|正しい文字コードで、ソースファイルが保存されていますか?EUC を指定して、もう一度確認してください。gedit で編集すると、SJIS になっているかもしれません。
:GUI の設定内容(ラベルテキストなど)を変えると、GUI の挙動がおかしくなる|別スレッドから値を変更していませんか?gtk_main() で待ち受けているスレッド以外から、GTK に変更を加えてはいけません。イベントなどを利用しましょう。タイマーイベントによるポーリングが有効かもしれません。また、ユーザー定義シグナルも使えるかもしれません。ただし後者については未調査です。

** 参考 [#lf431fe2]
- [[GTK+ リファレンスマニュアル:http://www.gnome.gr.jp/docs/gtk+-1.2.x-refs/gtk/]]
- [[Linux プログラミング研究室:http://www.sm.rim.or.jp/~shishido/linux.html]]

----
** 履歴 [#sf36cc0c]
- 2005年10月01日 初版

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS