ソフトウェア設計及び演習2015

GTK::超入門

GTK+超入門

Gtk入門資料です. 過去に鈴木先生がまとめられた資料です.

GTK+とGDK

GTK+ (GIMP ToolKit) は,ウィジェットライブラリです.

ウィジェット(widget) は小さな規格品の意味.GUIの部品を意味します.

以下のように分類しましょう:

  • 全てのウィジェット共通の機能
  • 似たウィジェット共通の機能
  • ウィジェット特有の機能

GDK (GIMP Drawing Kit) は描画のためのライブラリです.

ほとんど XLibと同じですが,GTK+ 用のインターフェイスを持っています.

GTK+ の表示はすべて,GDKを通して,XLib で行なわれます.

GTK+を用いたアプリケーションプログラムは GTK+, GDK, XLib, GLib, GObject を使うことになります.

GLibとGObject は GTK+やGDKで使うデータ型とそれらを使った一般的な関数を提供します.

g_pointer, GTK_OBJECT(), g_print, ...

Cライブラリが提供してくれる機能に皮をかぶせたり、機能を追加してりしています.

GTK+ を使ったプログラムのコンパイル方法

cc -Wall -g example.c -o example `pkg-config gtk+-2.0 --cflags` `pkg-config gtk+-2.0 --libs`
  • `pkg-config gtk+-2.0 --cflags` はインクルードファイルのパスなどを表示するコマンド. コンパイルに必要な情報 (コンパイラフラグ)を生成.` は ' ではないので注意.
  • cc -I はヘッダファイルのあるディレクトリの指定
  • csh の  は,の中をコマンドとして実行し,その結果で``を置き換える
  • `pkg-config gtk+-2.0 --libs` はライブラリのパス,ライブラリの指定などを表示すコマンド.リンクに必要な情報 (リンカフラグ)を生成.
  • cc -L はライブラリのあるディレクトリの指定
  • cc -l はライブラリの指定.-L /usr/X11R6/lib -lX11 は /usr/X11R6/libX11.so を意味する.

main 関数の流れ

例えば,日本語のメッセージのついたボタンを表示するプログラムは,次のような流れになります.

  • 初期化処理
    • ロケール設定
      • 国際化 (internationalization, i18nと略される) されたプログラムを
      • 地域化 (localization) する時につかう情報
      • LANG, LC_ALL, LC_COLLATE, ...
    • オプション処理
      • シェルのコマンドラインから与えられた gtk オプションの処理
        • rc と option の順番はこれでいい? 本にはこう書いてあるけれど,逆のような気がします
    • rcファイルの読み込み
      • スタイル設定, widget へのスタイル設定
      • 色とかフォントとかスタイル (Gcに相当)
  • ウィンドウ作成
    • ウィンドウ生成,
    • ボーダ幅設定 (枠)
    • コールバック関数の登録 (イベントを処理する関数)
  • ボタンの作成
    • ボタンを作り,
    • ウィンドウにのせる,
    • 可視化する
  • gtkの開始 -- イベントループ

GTK+ のプログラミングモデル

ウィジェット

各ウィジェットには,生成,操作を行なう関数がある.例えば,ボタンの場合

  • ボタンの作成
    • GtkWidget *gtk_button_new(void)
    • GtkWidget *gtk_button_new_with_label(gchar *)
シグナルの発生

ボタンに対するシグナルは

  • マウス操作で発生させるか
  • または以下の関数で発生させます.
    • void gtk_button_pressed(GtkButton *button)} "press" シグナル. マウスボタンが押された.
    • void gtk_button_released(GtkButton *button)} "release" シグナル.マウスボタンが離された
    • void gtk_button_clicked(GtkButton *button)} "clicked" シグナル. マウスボタンがクリックされた
    • void gtk_button_enter(GtkButton *button)} "enter" シグナル. マウスポインタが重なった
    • void gtk_button_leave(GtkButton *button)} "leave" シグナル.マウスポインタが外れた
シグナルとコールバック
  • シグナルが発生すると,それをきっかけに処理を行ないます.
  • シグナル駆動といいます.
  • シグナルにはタイマー割り込みもあります.
    • 一定時間間隔でシグナルが発生する.
  • 各ウジェットに対してシグナルを処理する関数の登録が行なえます.

8> gint g_signal_connect(GtkObject *object, gchar *name, GtkSignalFunc func, gpointer func_data)} >8

この関数をコールバック関数と呼ぶ.

ウィジェットの継承あるいは派生関係 (GTK+のデータ型)

ウィジェット間には親子関係を持つものがあります.

GtkObject -- GtkWidget -- GtkContainer -- GtkButton

  • GtkObject は GTK+ のすべてのオブジェクトが継承している型です.
  • GtkWidget は汎用的な(すべての Widget に共通する機能を持つ)ウィジェットを表し,GtkObject の一種です.
  • GtkContainer はウィジェットの一種でなかに他のウィジェットを含む事ができるコンテナ,
  • ボタンはコンテナの一種で,GtkButton は,GtkContainer がもつ一般的な機能を受け継ぎ,ボタンに特有な機能を追加 (あるいは置き換え) することで定義されています.

...という具合です。

GTK+では頻繁に型変換が必要になります.

  • 例えば,ボタンを作った場合,返される値の型は,GtkButtonではなくて,GtkWidgetです.
  • gtk_widget_show を使ってボタンも表示できますが,ボタン特有の関数を呼ぶ時には,GTK_BUTTON マクロによって GtkButton への型変換が必要になります.
  • ただし,ボタンへ変換できる型は,ボタン作成関数で作られたものか,ボタンから派生したものだけです.

プログラミング上のお約束

  • GTK+ で用意されているデータ型を使う事
  • ウィジェットを引数として使う場合にキャスティングすること

GDKとdrawing_area (簡単に)

後の見通しのために,GDK でできる事をまとめておきます.

  • GdkDrawable と GdkGC を使う.
  • GdkDrawable には GdkWindow, GdkPixmap, GdkBitmap がある.
  • GdkGC は XLib のGCと同じで,色,フォント,線の太さ,塗りつぶし方法などの記憶.
  • 機能としては,点,線,文字,円,円弧,四角を描くなどなど.
  • また,画像(Pixmapなど)を張り付けることなど.

例題プログラム

# include <gtk/gtk.h>

/* ボタンを押した時の処理 */

void button_was_clicked(GtkWidget *widget, gpointer data)
{
  g_print("Hello World Button is pushed!\n");
}

gint CloseAppWindow (GtkWidget *widget, gpointer gdata)
{
  g_print("QUitting ... ?n");
  gtk_main_quit();

  /* 終了作業を継続 */
  return(FALSE);
}

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

    /* 初期化: ロケール設定 */ 
    gtk_set_locale();

    /* 初期化: オプションの処理 */
    gtk_init( &argc, &argv );

    /* 初期化: rc ファイルの読み込み */
    gtk_rc_parse("./gtkrc");

    /* トップレベルウィンドウを生成 */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_signal_connect(GTK_OBJECT(window), "delete_event",
		       GTK_SIGNAL_FUNC(CloseAppWindow), NULL);

    /* コンテナ内のオブジェクトの周りにすき間を作成 */
    gtk_container_border_width(GTK_CONTAINER(window), 15);

    /* ボタンの作成 */
    button = gtk_button_new_with_label("Hello, World.\n");
    
    g_signal_connect(GTK_OBJECT(button), "clicked",
		       GTK_SIGNAL_FUNC(button_was_clicked), NULL);

    /* ボタンの配置 */
    gtk_container_add(GTK_CONTAINER(window), button);
    
    /* ボタンの表示 */
    gtk_widget_show(button);

    /* ウィンドウの表示 */
    gtk_widget_show(window);

    /* */
    gtk_main();

    /* 終了ステータスコード */

    return 0;
}


最終更新日:2015/03/05 10:01:29