Sep.04.1999
GTK+ と GLADE の組合せでポップアップメニューを作る方法についての説明です。 さらにポップアップメニューで選択された結果を元にウィンドウ内に画像を 表示する手順を模索します。
GLADE はインターフェースビルダーです。これでウィンドウの大きさや
ボタンの位置と言ったアプリケーションデザインを行い、GTK+ を用いた
基本的なソースコードを吐き出してもらいます。プログラマーはその吐き出された
コードに、各パーツの挙動をプログラミングすることによってアプリケーション
を作成します。画面デザインやインターフェースの作成という案外冗長で
重たい作業を軽減するためのツールです。
作業手順を考えるとわかるのですが、アプリケーションを作っている最中に
インターフェースを修正するといった作業は結構大変です。こればっかりは
他の環境に統合されていない限り難しいので、現在の GLADE の問題点と言った
ところでしょうか。
ですから、なるべく GLADE が吐き出すソースは後で上書きしても良いように
なるべくいじらないで新規にソースを起こし、そっちに処理を書くといった
ことを心がける必要がありそうです。
取り敢えず、今回
目的となるインターフェースを作成します。
256x256Pixel サイズのメインウィンドウ一つに全面 Drawing Widget を
張り付けておきます。この Drawing Widget に画像を表示する予定です。
メインウィンドウと別にポップアップメニューを作成します
(GTK+ Additional の方にあります)。
メニュー項目ひとつひとつにハンドラを指定しておいてください。
メインウィンドウとなるウィンドウに Destroy ハンドラを設定するのを
忘れないでください。Window Maneger によって Window が閉じられても
アプリケーションは終了しませんから、この Destroy シグナルで Window が
(ある意味強制的に)閉じられたことを検出する必要があるわけです。
ハンドラ側のコードは以下の通りになります。(callbacks.c)
void on_window1_destroy (GtkObject *object, gpointer user_data) { gtk_main_quit(); }毎回必要になる常套句です。
今回目的とするアプリケーションは
以上でインターフェースの作成は終了。セーブし、ソースを生成します。 以上の作業をセーブしたファイルです→ popup.glade
GLADE にソースを吐き出させると src/ ディレクトリ下に以下のファイルが 生成されていることがわかるとおもいます。
callbacks.[h|c] interface.[h|c] support.[h|c] main.cこの中でプログラマが手を加えることを許されているのは main.c と callbacks.c の様です。その他、特に interface.[c|h] は GLADE が ソースを生成する度に書き直されますので、ここにプログラマーが コードを書くのは避けてください。
GLADE で PopupMenu を作成しても、生成のためのコードが作られるだけで
そのままではメニューは現れません。ポップアップメニューが現れるのは
ボタンクリックだけとは限りませんから、どうやったらメニューが現れるかを
インプリメントする必要があります。
今回はウィンドウ上でマウスの Button3 をクリックしたらポップアップメニューが
表示されるといった形で作成することにします。
ポップアップメニューの名称を "popupmenu" として GLADE でソース生成を すると、interface.c 内に create_popupmenu なる関数が生成されます。 これをコールすると Menu Widget が生成されますが、表示はされません。 その後に gtk_menu_popup を実行すると、目的とするポップアップメニューが 現れ、機能します。メニュー内のハンドラが正しく記述されていれば、選択項目に 応じてハンドラがコールされますので目的は達成されます。
ボタンクリックからポップアップメニューまでの具体的なコードは以下の様に なります。(大部分を Gtkリファレンスから引用)
gboolean on_drawingarea1_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { GtkMenu *menu; GdkEventButton *event_button; menu = GTK_MENU (create_popupmenu()); g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE); /* The "widget" is the menu that was supplied when * gtk_signal_connect_object was called. */ if (event->type == GDK_BUTTON_PRESS) { event_button = (GdkEventButton *) event; if (event_button->button == 3) { gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time); return TRUE; } } return FALSE; }
ウィンドウ上にある Drawarea に Pixmap を表示する手法を解説します。
GLADE には Pixmap というパーツがあるのですが、特定の Pixmap を置いておく
には簡単ですがダイナミックに描き変わるといった用途にはさほど向いていない
ようなので、自前でメモリー上に Pixmap を用意しそれを Drawarea に描き込む
方法をとります。将来的にダブルバッファとかを用意するための基礎とも
なりますので。
まずは XPM 形式のグラフィックファイルを「インクルード」して Pixmap を
生成する方法から。
ASCII形式の XPM ファイルはそのままテキストファイルとして覗けばわかるように
C のデータ形式をしています。これを Gdk で利用するには「ファイルとしてデータ
を置きそれを読み込む」方法と、「コードとしてインクルードしてバイナリに含めて
しまう」といった方法の2つがあります。
GLADE ではなにかとファイル形式にしてしまいます。これはこれで良いのですが、
インストール先に pixmap/ というフォルダを作りそこにファイルをおさめると
いった形になります。ほんのちょっとしたデータでもこれをやられるのはちょっと
うざったいのでケースバイケースということで、今回はコードとして埋め込む
方式にしてみましょう。
XPM データはソース内で include してしまいます。
#include "../picture/pic1.xpm" #include "../picture/pic2.xpm"それぞれのデータポインタが pic1_xpm, pic2_xpm とした場合、これらデータ ポインタから pixmap を生成するのは gdk_pixmap_create_from_xpm_d という gdk関数を使います。
{ GdkPixmap *pixmap[2]; GdkBitmap *mask[2]; /* Pixmap の作成 */ pixmap[0] = gdk_pixmap_create_from_xpm_d(mainwin->window, &mask[0], NULL, pic1_xpm); pixmap[1] = gdk_pixmap_create_from_xpm_d(mainwin->window, &mask[1], NULL, pic2_xpm); }そうやって作成した Pixmap と Mask があるとして、それらを Drawarea に 表示する手順は以下の様になります。(詳細省略)
{ gdk_window_get_size(pixmap[n], &w, &h); gdk_gc_set_clip_mask(win_gc, mask[n]); gdk_gc_set_clip_origin(win_gc, 0, 0); gdk_draw_pixmap(canvas->window, win_gc, pixmap[n], 0, 0, 0, 0, w, h); gdk_gc_set_clip_mask(win_gc, NULL); }canvas は Drawarea の GtkWidget* を表します。win_gc は グラフィックコンテキストで
{ /* GC の作成 */ win_gc = gdk_gc_new(mainwin->window); }で生成されています。
細かい関数仕様などは Gtkリファレンスを参照したりしてください。
全体的なコード例 "paint.c"
#エラーチェックとか甘甘 :-P
GLADE でコードを生成すると autogen.sh なるスクリプトが作られます。
これを実行すると configure が生成された後、実行され Make の準備が
整います。その後 make したり make install したりします。
で、そのなかに make dist というものがあります。これは配布に必要な
一式をまとめ tarball 形式のソース配布形式を作成するものです。
(バージョンナンバーもファイルネームに含まれる)
自分でソースを追加した後とかだとそのままってわけにいきませんから
この make dist ができるように configure.in や Makefile.am をちょっと
書き直しましょう。
ソースルート(README や configure があるフォルダ)になにかしら
新規フォルダを追加した場合それをソースルートの Makefile.am に記録します。
今回は GLADE が生成する intl, po という二つのソースディレクトリを
使いませんのでそれを削除し、src のみを残します。
tarball作成に picture というディレクトリの画像データが必要なので、
dist-hook: というターゲットを書き換えて picture に準じるようにします。
多分デフォルトだと pixmap を扱うために存在しているはずです。もし、
pixmap ディレクトリも必要ならコピーして併記にしましょう。
pixmap インストールに必要な install-data-local: は今回必要無いんで
削っちゃいます。
configure.in の中に、Makefile を実行する手順が AC_OUTPUT に書いてあります。
今回 intl/, po/ はいらないので削っておきます。それと、バージョンナンバー
も正しく記載しておきましょう。
src/ 内にソースを追加している場合 src/Makefile.am の 〜_SOURCES にそれら
を追加します。
それら変更が終ったら autogen.sh を実行して autoconf を起動、configure を
作成します。ここまで問題なくできたら make all, make install, make dist が
実行できると思います。
詳しいことは autoconf や automake の利用法を調べてみてください。
配布条件はソース/データ共に GPL に準ず。