2007年10月19日

[011]原始的な描画プログラム〜その2〜

前回はマウスポインタの動きに追従して伸び縮みする線(ラバーバンド)を描画することをテーマに扱いました。

今回は、このラバーバンドを前々回の「原始的な描画プログラム」に応用してこのプログラムを少しだけ進化させてみました。

ソースです→LineDrawing2.tar.gz

解凍してできたLineDrawing2という名前のディレクトリの中のLineDrawing2.prjをanjutaで開けば好きなように料理できる筈です。


各ウィジットのプロパティ

今回も使っているウィジットはメインのウインドウであるwindow1と、描画領域のdrawingareaの2つのみです。window1の中にdrawingareaを直接貼り付けています。赤い字のところは追加または変更があったプロパティです。


[window1]
タイトル→「直線描画パート2」
シグナル→「destroy」
ハンドラ→「gtk_main_quit」


[drawingarea]
名前→「drawingarea」
イベント→「00000000000100000100」(GDK_POINTER_MOTION_MASK,GDK_BUTTON_PRESS_MASK)
シグナル→「realize」
ハンドラ→「on_drawingarea_realize」

シグナル→「button_press_event」
ハンドラ→「on_drawingarea_button_press_event」
シグナル→「motion_notify_event」
ハンドラ→「on_drawingarea_motion_notify_event」



イベント処理

ソースです→callbacks.c



ウィジットの背景色の取得について

今回のプログラムではdrawingaraの背景色は弄らずにデフォルトのままにしています。
ラバーバンドの前景色を設定する際にdrawingareaの背景色を使うので、以下のようにしてdrawingareaの背景を取得しています。
GtkStyle *style = gtk_widget_get_style(widget);
GdkColor bgcolor=style->bg[0];


イベントハンドラのブロックについて

今回のプログラムではマウスポインタが動いたというシグナル("motion_notify_event")に対して呼び出される処理としてon_drawingarea_motion_notify_eventハンドラを登録しています。
そしてこのon_drawingarea_motion_notify_eventの中でラバーバンドの描画を行っています。

ところで私がこのプログラムに望む動作は、直線の始点をクリックしてから終点をクリックするまでの間だけラバーバンドを描画してくれることです。

この目的のために、今回のプログラムでは始点がクリックされてから終点がクリックされる間以外は次のようにしてon_drawingarea_motion_notify_eventの動作を一時的にブロックしています。
g_signal_handlers_block_by_func(G_OBJECT(widget), G_CALLBACK(on_drawingarea_motion_notify_event),NULL);


またブロックの解除は次のようにして行います。
g_signal_handlers_unblock_by_func(G_OBJECT(widget), G_CALLBACK(on_drawingarea_motion_notify_event),NULL);


もちろんon_drawingarea_motion_notify_eventをブロックするのではなく、on_drawingarea_motion_notify_eventの内部でクリック回数によってラバーバンドの描画を行うかどうかの条件分岐を行ってもかまいません。
またあるいは関数のポインタを使うという手もあります。



お願い


もし、GtkおよびGlibのシグナルについてお詳しい方がおられましたら2つ程教えていただけないでしょうか?

今回g_signal_handlers_block_by_funcという関数を使っていますが、
http://www.gnome.gr.jp/docs/gtk+-2.0.x-tut/ch-advancedeventsandsignals.html
によると、
void g_signal_handlers_block_by_func(GObject *object,GCallback func,gpointer data );

となっています。また
http://www.gnome.gr.jp/docs/glib-2.8.x-refs/gobject/gobject-Signals.html#g-signal-handlers-block-by-func
によれば
g_signal_handlers_block_by_func()

#define g_signal_handlers_block_by_func(instance, func, data)

func と data が一致するインスタンスのハンドラを全てブロックします。
instance : ブロックするハンドラのインスタンス
func : ハンドラのC言語クロージャのコールバック (C言語以外のクロージャを除く)
data : func のデータ 返り値 : ブロックしたハンドラの数

となっています。instanceにはGtkWidgetのポインタをGObject型にキャストすればよく、funcにはシグナルハンドラとなる関数のポインタをG_CALLBACKマクロでGCallback型にキャストして渡せば良いらしいということが分かったのですが、3番目の引数dataがなんなのかが分かりません。今回のプログラムではNULLを渡してごまかしています。

教えていただきたい事の一つ目というのはこの3番目の引数dataとはいったい何ぞやということです。


二つ目の疑問もシグナルに関係することです。シグナルハンドラをブロックすることを調べていて最初に出てきた関数はg_signal_hander_blockというものです。
http://www.gnome.gr.jp/docs/glib-2.8.x-refs/gobject/gobject-Signals.html#g-signal-handler-block
には次のように説明されています。
g_signal_handler_block ()
void g_signal_handler_block(gpointer instance,gulong handler_id);

インスタンス上でシグナル・ハンドラの呼び出しをブロックするので、たとえシグナルが発行されても、再びそのブロックが解除されるまで指定したハンドラは呼び出されません。

handler_id には inscance のシグナルに接続する適切なシグナル・ハンドラの識別子を指定して下さい。
instance :ブロックするシグナル・ハンドラのインスタンス
handler_id : ブロックするハンドラの識別子


最初、こちらの関数を使おうかと思ったのですが、handler_idをどうやって取得すればよいかが分かりませんでした。
つまり教えていただきたい事の二つ目はこのhander_idをどうやって取得すれば良いのかということです。

もしこれらの疑問に対する答をお持ちでしたら下のコメントに書き込みをお願いいたします。
posted by knyakki at 10:01| Comment(2) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
失礼いたします
Posted by エロ at 2008年01月25日 23:49
もう解決されたかもしれませんが・・・

1つ目は
g_signal_connectもしくはgtk_signal_connectでhandlerをセットする際に第4引数に指定したfunc_dataだと思います

2つ目はg_signal_connect/gtk_signal_connectの戻り値がhandler_idではないでしょうか。

Posted by ハルパパ at 2008年06月22日 06:55
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。