[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][TOP]
わたしも done
お世話になります。
LASER5 石田絵理です。
本当は, 昨日報告したかったんですけど
中井さんより一日遅れです。
GGAD gtk.sgml 終わりました。
なにか指摘していただけたら幸いです。
下記のような感じで訳しました。
Accessor - アクセス構造
descriptor - 記述子
floating - フローティング
homogeneous - 均一
geometry - ジオメトリ
ghosted - ゴースト化
grab - グラブ
grid - グリッド
instance - インスタンス
mapping - マッピング
navigation - ナビゲーション
non-homogeneous - 非均一
pack - パック
padding - パディング
predicate - 属性
Prelight: - プレライト
realizing - リアライズ
reference - レファレンス
sensitivity - 応答
sequence - 逐次処理
session - セッション
sink - シンク
添付してあります。
cvs で commit しようと思ったんですけどなぜかできなくなってしまいました。
[eri@eri GGAD]$ cvs ci sgml/gtk.sgml
cvs [server aborted]: "commit" requires write access to the repository
となっちゃうんです。
1ヶ月近くたつと使い方忘れるのはやめて下さいといわず,
草野さん助けて下さい。
いつもすみません。
--
Eri ISHIDA <eri@xxxxxxxxxxxx>
LASER5 <http://www.laser5.co.jp/>
<chapter id="cha-gtk">
<title>GTK+ の基本</title>
<para>
この章は, 通常の Hello, World に値する GTK+の概要についてです。そして,
GTK+アプリケーションの開発を始めるにあたって必要となる本質的細部に話題を
のばしています。
</para>
<para>
既に, GTK+チュートリアル
<ulinkurl="http://www.gtk.org/" type="http">http://www.gtk.org/</ulink>,
または <emphasis>Developing Linux Applications with Gtk+ and Gdk</emphasis>
( 同 New Riders出版発刊 )を読まれている場合は, この章を飛ばしたり,
軽く目を通すくらいでいいかもしれません。今までに, GTK+を使ったことがない
ならば, 直ちにこの章を読み始め, よく理解して下さい。
</para>
<sect1 id="sec-gtk-tour">
<title>GTK+旋風旅行</title>
<para>
GTK+のオブジェクト指向コーディング形式, 簡潔した設計,
そしてAPI-命名規定に対する慎重な配慮は, プログラム書きやすく,
かつ理解しやすいものにしています。ここで, この点を確証するためGTK+
での完全 "Hello, World" を紹介します。全くGTK+の経験がないとしても,
コードの80%がどのようになるかをおおよそ予想できるでしょう。
</para>
<sect2 id="sec-gtk-hello">
<title>完全な Hello, World</title>
<figure float="1" id="fig-gtk-hello">
<title>Hello, World</title>
<graphic fileref="figures/hello" format="png"></graphic>
</figure>
<programlisting>
#include <gtk/gtk.h>
static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data);
static void button_click_cb(GtkWidget* w, gpointer data);
int
main(int argc, char* argv[])
{
GtkWidget* window;
GtkWidget* button;
GtkWidget* label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new();
label = gtk_label_new("Hello, World!");
gtk_container_add(GTK_CONTAINER(button), label);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_window_set_title(GTK_WINDOW(window), "Hello");
gtk_container_set_border_width(GTK_CONTAINER(button), 10);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(delete_event_cb),
NULL);
gtk_signal_connect(GTK_OBJECT(button),
"clicked",
GTK_SIGNAL_FUNC(button_click_cb),
label);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static gint
delete_event_cb(GtkWidget* window, GdkEventAny* e, gpointer data)
{
gtk_main_quit();
return FALSE;
}
static void
button_click_cb(GtkWidget* w, gpointer data)
{
GtkWidget* label;
gchar* text;
gchar* tmp;
label = GTK_WIDGET(data);
gtk_label_get(GTK_LABEL(label), &text);
tmp = g_strdup(text);
g_strreverse(tmp);
gtk_label_set_text(GTK_LABEL(label), tmp);
g_free(tmp);
}
</programlisting>
<sect3 id="sec-gtk-comphello">
<title>Hello, Worldのコンパイル</title>
<para>
GTK+ には, <application role="tt">gtk-config</application>という
シェルスクリプトが付属しています。このスクリプトは, GTK+が構築
されると作成されます。その目的は, GTK+プログラムをコンパイルする
のに必要とするコンパイラのフラグを伝えることです。以下のシェル
セッションでは, その特徴を示しています。
</para>
<programlisting>
$ gtk-config --version
1.2.0
$ gtk-config --prefix
/home/hp/local
$ gtk-config --exec-prefix
/home/hp/local
$ gtk-config --libs
-L/home/hp/local/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXext -lX11 -lm
$ gtk-config --libs gthread
-L/home/hp/local/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lgthread -lglib -lpthread -ldl -lXext -lX11 -lm
$ gtk-config --cflags
-I/usr/X11R6/include -I/home/hp/local/lib/glib/include -I/home/hp/local/include
$
</programlisting>
<para>
<application role="tt">bash</application>のような,
Bourneシェルと異なるシェルをお使いの場合,
<application role="tt">gtk-config</application>を実行する際
バックチェック (シングルクォートは,
<emphasis>不可</emphasis>)を用いて, その出力を変更することができ
ます。
Hello, Worldをコンパイルする簡単な<filename>Makefile</filename>は,
次のようになります。
</para>
<programlisting>
CC=gcc
all: hello.c
$(CC) `gtk-config --libs` `gtk-config --cflags` -o hello hello.c
clean:
/bin/rm -f *.o *~
</programlisting>
<para>
もちろん, この <filename>Makefile</filename> は, 現実のアプリケー
ションとしては, 単純すぎます。 <xref linkend="cha-source">
では, <application>automake</application>及び
<application>autoconf</application>を使ったより現実的な構築方法を
解説しています。
</para>
<para>
<application role="tt">gtk-config</application> は, ユーザの
システムに<filename>Makefile</filename>で位置のハードコーディング
を行わずに, GTK+を位置付けられるようになります。ご自身のシステム
上に, 2つのバージョンのGTK+が存在すると, それもまた何かと便利です。
専用のディレクトリツリーにそれら各々をインストールしていると,
シェルの検索パスに<application role="tt">gtk-config</application>
を置くことで, どちらか一方を選択できるようになります。
</para>
</sect3>
</sect2>
<sect2 id="sec-gtk-how">
<title>動作の仕様</title>
<para>
この簡単なプログラムは, GTK+アプリケーションの本質的要素を全て
含んでいます。Gnomeの特徴は含んでいませんが, Gnome は GTK+上で構築
しているので, 同様の概念があてはまります。
</para>
<sect3 id="sec-gtk-i18n">
<title>初期化</title>
<para>
まず, GTK+ は初期化されなければなりません。
</para>
<programlisting>
gtk_init(&argc, &argv);
</programlisting>
<para>
このコールはXサーバへ接続し, 全GTK+プログラムで解釈された
デフォルト引数を解析します。解析された引数は,
<structname role="C">argv</structname>から取り除かれ,
そして<structname role="C">argc</structname>も, それに応じて削除され
ます。<function>gtk_init()</function>は,
また<function>atexit()</function> を使って"初期化機能"を登録し
ます。実際は, <function>fork()</function>の時のみ重要です。
というのは子プロセスは, 親プロセスでのGTK+をシャットダウン
をさけるため<function>exit()</function>よりもむしろ
<function>_exit()</function>を使って終了しなければならないからです。
</para>
</sect3>
<sect3 id="sec-gtk-widgets">
<title>ウィジェット</title>
<para>
どのようなプログラムでもあるユーザインターフェスを持ち
ます。X の伝統として, これらは<firstterm>ウィジェット</firstterm>と
いわれます。全てのウィジェットが,
<classname role="widget">GtkWidget</classname>基本クラスのサブクラス
です。そのため, ウィジェットを参照する際
<structname role="C">GtkWidget*</structname>を使うことできます。
( Cには, 元来オブジェクト継承に対するサポートが存在しないため, GTK+
は独自のメカニズムが存在します。—<xref linkend="cha-objects">
で, これについて解説してあります。)
</para>
<programlisting>
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new();
label = gtk_label_new("Hello, World!");
gtk_container_add(GTK_CONTAINER(button), label);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_window_set_title(GTK_WINDOW(window), "Hello");
gtk_container_set_border_width(GTK_CONTAINER(button), 10);
</programlisting>
<para>
それぞれのウィジェットが<function>gtk_widgetname_new()</function>を
コールする関数を持っています。それは C++または, Javaの
コンストラクタと類似します。この関数は, 新たなオブジェクトを割り当て,
それを初期化し, それに対するポインタを返します。
全<function>_new()</function>ルーチンが,
<structname role="C">GtkWidget*</structname>を返します。
たとえそれらがサブクラスを配置していたとしてもです。これは,
好都合な機能です。
</para>
<para>
オブジェクトを表すのに
<structname role="C">GtkWidget*</structname>を用いると, その手段を
使って, オブジェクトを処理することができます。全てのGTK+
ウィジェット関数が作用する型の名称で始まり, 第1引数としてその型への
ポインタを受け入れます。上記のコードで,
<function>gtk_container_add()</function>は
第1引数として<structname role="C">GtkContainer*</structname>を
受け入れています。<function role="macro">GTK_CONTAINER()</function>
マクロは, <structname role="C">GtkWidget*</structname>をキャストし,
実行時の型チェックも行います。キャストが要求されるのは, Cが継承関係
を解釈しないためです。
</para>
<para>
想像がつくかもしれませんが,
<classname role="widget">GtkButton</classname>と
<classname role="widget">GtkWindow</classname>は, 共に
<classname role="widget">GtkContainer</classname>のサブクラスです。
<classname role="widget">GtkContainer</classname>は, 他のどの
ウィジェットも内部に持つことができます。コードはトップレベル
ウィンドウを作成し, その内部にボタンを設置し, そのボタンの内部に
ラベル( テキストライン )を置きます。そして, ウィンドウのタイトルを
設定し,ボタンの周りに小さな装飾的境界線を追加します。
</para>
</sect3>
<sect3 id="signals">
<title>シグナル</title>
<para>
次に, ユーザがウィジェットを処理する際の反応の構成について考えたいと
思うことでしょう。この簡単なアプリケーションでは,
起こりうる2つの興味深い事象があります。ユーザはボタンを
クリック, またはウィンドウマネージャの装飾的機能を使ってウィンドウ
を閉じることができるのです。ウィジェット( 実上は, 全 <structname
role="C">GtkObject</structname> )は, プログラムが反応を必要とする
かもしれない何かの事象が生じると,
<firstterm>シグナル(signals )</firstterm>を送出します。
シグナルへの反応は, "コールバックに繋がり"ます。—
シグナルが送出されると, コールされる関数を登録します。
ここに再度コードをあげておきます。
</para>
<programlisting>
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(delete_event_cb),
NULL);
gtk_signal_connect(GTK_OBJECT(button),
"clicked",
GTK_SIGNAL_FUNC(button_click_cb),
label);
</programlisting>
<para>
<function>gtk_signal_connect()</function> は, モニタ上の <structname
role="C">GtkObject</structname>, 接続用のシグナル,
接続へのコールバック, そして最後に
<structname role="C">user_data</structname>引数を指定します。
—これは特殊な<structname role="C">gpointer</structname>で,
コールバックへ渡されます。マクロ
<function role="macro">GTK_SIGNAL_FUNC()</function>は, 標準関数
の合図へコールバックをキャストします。コールバックには様々の
合図の型が存在するので, 代替は
<function>gtk_signal_connect()</function>の変化で数十にもなる
でしょう。
</para>
<para>
GTK+ は, 起動時に多くの分別的なチェックを行います。
<function role="macro">GTK_OBJECT()</function>マクロは Cのキャスト
に加え, 起動時の型チェックも含んでいます。
<function>gtk_signal_connect()</function>は, オブジェクトが実際に
指定したシグナルを送出しているか確認します。
</para>
</sect3>
<sect3 id="sec-gtk-entloop">
<title>メインループの記述</title>
<para>
全てが設定されても, 2つのステップが残っています。画面上に
ウィンドウを表示し, ユーザの入力を待つ必要があります。
</para>
<programlisting>
gtk_widget_show_all(window);
gtk_main();
return 0;
</programlisting>
<para>
<function>gtk_widget_show_all()</function> は, 再帰的に
<function>gtk_widget_show()</function>をコンテナ上, または
その子プロセスでコールします。次のコードは, この場合, 同じ効果を
持つでしょう。
</para>
<programlisting>
gtk_widget_show(label);
gtk_widget_show(button);
gtk_widget_show(window);
</programlisting>
<para>
画面上表示したい各々, そして全ウィジェットを示す必要があります。
それに対する操作は, <function>gtk_widget_hide()</function>です。
ウィジェットは, その隠れたライフを始め, 何回でも再隠再出すること
ができます。最外部のコンテナを表示する前に全子ウィジェットを表示
するのは効果的です。さもないと, ユーザはコンテナがまず現れた後,
その子が続くようになります。ウィジェットは, その親コンテナが
表示されるまで実際の画面には現れません。—この規則の例外は,
<classname role="widget">GtkWindow</classname>で, これは親を持ち
ません。
</para>
<para>
ウィジェットが表示されると, ユーザがそれを使って何か行うのを期待
するでしょう。<function>gtk_main()</function>は, GTK+のメインループ
に入ります。メインループはイベント操作です。つまり, ユーザの行動が
<firstterm>イベント(events)</firstterm>に対してトリガ(trigger)を
行います。そのイベントは, 通常送出されているシグナルやコールされた
コールバックで反映されます。
<function>gtk_main()</function> は漠然にブロックを行い, ユーザの
入力を待ち, それに応答します。メインループに関するさらなる詳細は,
<xref linkend="sec-mainloop">で解説されています。イベントやメイン
ループとの関係は, <xref linkend="sec-gdkevent">で説明されています。
</para>
</sect3>
<sect3 id="sec-gtk-callbacks">
<title>更にシグナルとコールバックについて</title>
<para>
プログラムが接続するシグナルのどれかが送出されると, それに対応する
コールバックがコールされます。
<symbol role="signal">"delete_event"</symbol>コールバックは,
<function>gtk_main_quit()</function>をコールすることで
<function>gtk_main()</function>イベントループを終了します。これは
プログラムを終了時に, <function>gtk_main()</function>を復帰させ
ます。<symbol role="signal">"clicked"</symbol>コールバックは,
逆にテキストを同じテキストを用いたラベルに置き換えます。ラベルは,
<function>gtk_signal_connect()</function>への
<structname role="C">user_data</structname>パラメータとして
コールバックに渡されたという点に注意して下さい。
</para>
<para>
よくある間違いは, 全てのシグナルが同種のコールバックを用いていると
思っている点です。—実際は違います。各シグナルが特定の型の
合図や独自の振る舞いを用いてコールバックを要求します。
<symbol role="signal">"clicked"</symbol>シグナルは, 非常にありふれた
コールバック型を取ります。このコールバックは, シグナルを送出している
ウィジェットへのポインタやプログラマによって提供された
全<structname role="C">user_data</structname>を受け取ります。
このコールバックは, <structname role="C">void</structname>を
返さ<emphasis>なければならず</emphasis>, さもないとメモリの腐敗が
発生するかもしれません。
</para>
<para>
一方, <symbol role="signal">"delete_event"</symbol>は, 特別です。
3つの引数を受け入れます。第1と第3は,
<symbol role="signal">"clicked"</symbol>と類似しますが,
第2はシグナルをトリガしたイベントへのポインタです。
(<firstterm>イベント(events)</firstterm> は, Xからアプリケーション
へのメッセージで, マウスの動作, キー入力等を報告します。) <symbol
role="signal">"delete_event"</symbol> コールバックは, "不思議な"値
を返します。—<structname role="C">FALSE</structname>が返され
ると, GTK+はウィンドウを破棄します。
<structname role="C">TRUE</structname> が返されるとGTK+は,
なにも行いません。もしウィンドウの破棄以外の処理を要するなら,
<structname role="C">TRUE</structname>を返して下さい。例えば,
ユーザに保存されていないドキュメントについて警告したい場合などが
考えられます。
</para>
<para>
ウィジェットのヘッダファイルは, コールバックの合図に関して
最も優れたクイックリファレンスです。ウィジェットの"クラス構造"は,
デフォルトのシグナルハンドラのための領域が存在します。
ハンドラは, デフォルトに沿って作成されるべきでしょう。例えば,
<filename role="header">gtk/gtkbutton.h</filename>では
<classname role="widget">GtkButton</classname>クラス構造は,
次のようになります。
</para>
<programlisting>
struct _GtkButtonClass
{
GtkBinClass parent_class;
void (* pressed) (GtkButton *button);
void (* released) (GtkButton *button);
void (* clicked) (GtkButton *button);
void (* enter) (GtkButton *button);
void (* leave) (GtkButton *button);
};
</programlisting>
<para>
<xref linkend="cha-objects"> では, クラス構造が何に対するものかを
的確に解説しています。今のところは関数ポインタに注意を払い, それらが
シグナルに一致するという点に注目して下さい。次のような書き方から,
</para>
<programlisting>
void (* clicked) (GtkButton *button);
</programlisting>
<para>
このようになります。
</para>
<programlisting>
static void button_click_cb(GtkWidget* w, gpointer data);
</programlisting>
<para>
単に, <structname role="C">gpointer data</structname>をクラス構造
関数の合図に追加しただけです。Hello, World では, 型を
<structname role="C">GtkButton*</structname>から
<structname role="C">GtkWidget*</structname>に変更しました。これは,
共通しています。<structname role="C">GtkWidget*</structname>を使うと
より便利です。引数は, 常にシグナルを送出している
<classname role="widget">GtkButton</classname>です。
</para>
<para>
次の例も役立つでしょう。
これは, <filename role="header">gtk/gtkwidget.h</filename>の
<symbol role="signal">"delete_event"</symbol>です。
</para>
<programlisting>
gint (* delete_event) (GtkWidget *widget,
GdkEventAny *event);
</programlisting>
<para>
そして, Hello, World からのコールバックです。
</para>
<programlisting>
static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data);
</programlisting>
<para>
それだけのことです。この章で紹介した情報のみで,
簡単なGTK+アプリケーションを書くこともできます。
GTK+ と GNOME は強力なアプリケーション開発ツールです。というのは,
画面上にウィンドウを作成するのに苦労せず, 実際の機能性について
考えることができるからです。
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="sec-containers">
<title>コンテナとウィジェットレイアウト</title>
<para>
GTK+には, 2種類のコンテナウィジェットがあります。全コンテナウィジェット
が, 抽象的<classname role="widget">GtkContainer</classname>のサブクラス
です。コンテナウィジェットの最初の型は,
常に<classname role="widget">GtkBin</classname>から伝わり, もう一方は
抽象的基本クラスです。<classname role="widget">GtkBin</classname>の
降下は, 子ウィジェットを1つだけ含むことができます。
これらのコンテナは, 子に対して数種の機能性を追加します。例えば,
<classname role="widget">GtkButton</classname>は<classname
role="widget">GtkBin</classname>です。これは子にクリック可能なボタンを
作成します。<classname role="widget">GtkFrame</classname>は, <classname
role="widget">GtkBin</classname>で, 子のまわりに簡単な境界線を描きます。
<classname role="widget">GtkWindow</classname>では, 子がトップレベルの
ウィンドウに表示可能になります。
</para>
<para>
コンテナウィジェットの第2の型は, その直属の親として頻繁に<classname
role="widget">GtkContainer</classname>を持ちます。これらのコンテナは,
1つ以上の子を持ちます。それらの目的は, レイアウト管理です。
"レイアウト管理"とは, これらのコンテナがそれを含むウィジェットに対して
<emphasis>サイズ</emphasis>と<emphasis>配置</emphasis>を割り当てる
ということですます。
例えば, <classname role="widget">GtkVBox</classname>は, 垂直スタックで
その子を配置します。<classname role="widget">GtkFixed</classname>は,
任意の座標に子を配置できます。
<classname role="widget">GtkPacker</classname>は, Tk-形式のレイアウト
管理が可能になります。
</para>
<para>
この章は, 2つめのコンテナについてです。サイズに対してハード
コーディングせずにレイアウトを作成するには, これらの使い方を理解する
必要があります。最終目標は, 仮のウィンドウサイズ, 画面サイズ,
ウィジェットの外観, フォントなどを作成しないようにすることです。
これらのファクタが変化したら, アプリケーションが自動的に適応すべき
でしょう。
</para>
<sect2 id="sec-sizenegotiation">
<title>サイズの割り当て</title>
<para>
レイアウトコンテナを理解するには, まずGTK+ウィジェットがそのサイズを
どのように調整しているのか理解しなければなりません。
ところが実は割と単純で, 2つの概念
<firstterm>要求(requisition)</firstterm>と
<firstterm>割り当て(allocation)</firstterm>のみです。
これらは, レイアウトの2面性にあたります。
</para>
<sect3 id="sec-gtk-requisition">
<title>要求</title>
<para>
ウィジェットの<firstterm>要求(requisition)</firstterm>は, 幅と高さ
—予定的ウィジェットサイズで成り立ちます。これは,
<structname role="C">GtkRequisition</structname>構造で表現されます。
</para>
<programlisting>
typedef struct _GtkRequisition GtkRequisition;
struct _GtkRequisition
{
gint16 width;
gint16 height;
};
</programlisting>
<para>
それぞれのウィジェットが, それぞれの方法でどのようなサイズを要求
しているか選択します。例えば,
<classname role="widget">GtkLabel</classname>は,
ラベルで全テキストを表示するのに必要なサイズを要求します。多くの
コンテナウィジェットは, その子のサイズ要求をもとにサイズ要求の
基礎を形成します。例えば, いくつかのボタンをボックスに置くと,
ボックスは全てのボタンを保持できるくらいの十分な大きさがあるか
問いかけます。
</para>
<para>
レイアウトの初段階は, <classname role="widget">GtkWindow</classname>
のようなトップレベルウィジェットから始まります。これはコンテナ
なので, <classname role="widget">GtkWindow</classname>はその
子ウィジェットにサイズ要求を尋ねます。その子は, それ自身の子に
といったように再帰的に行われます。全子ウィジェットが尋ねられると,
<classname role="widget">GtkWindow</classname>は最終的に
その子から<structname role="C">GtkRequisition</structname>に戻って
きます。どのように設定されたかによるので, <classname
role="widget">GtkWindow</classname>はサイズ要求に適応するため拡張
できるかもしれないし, できないかもしれません。
</para>
</sect3>
<sect3 id="sec-gtk-alloc">
<title>割り当て</title>
<para>
レイアウトの段階2は, ここから始まります。<classname
role="widget">GtkWindow</classname>は, その子に対して実際どれくらいの
容量が可能であるか決定し, その決定を子に伝えます。これは, 子の
<firstterm>割り当て(allocation)</firstterm>として知られており,
次のような構造で表現されます。
</para>
<programlisting>
typedef struct _GtkAllocation GtkAllocation;
struct _GtkAllocation
{
gint16 x;
gint16 y;
guint16 width;
guint16 height;
};
</programlisting>
<para>
<structname role="C">width</structname> や <structname
role="C">height</structname>の要素は,
<structname role="C">GtkRequisition</structname>と同一です。
それらは, ウィジェットのサイズを表現します。
<structname role="C">GtkAllocation</structname>もまたその親への配慮
を伴って子の座標を取り込みます。
<structname role="C">GtkAllocation</structname>
は, それらの親コンテナによって子に割り当てられます。
</para>
<para>
ウィジェットは, それらに与えられた
<structname role="C">GtkAllocation</structname>を尊重することを
要求されます。<structname role="C">GtkRequisition</structname>は,
単なる要求です。ウィジェットは, どんなサイズにも対処できなければ
なりません。
</para>
<para>
レイアウト課程を与えられると, コンテナがどのような役割をしているか
容易にみることができます。それらのジョブは, 各子の要求を
ウィジェットツリー上を通過したシグナルの要求に集まります。そして,
割り当てを分割するために, 子の間で受け取ります。これが,
正確にはどのように行われているかは, 特定のコンテナに依存します。
</para>
</sect3>
</sect2>
<sect2 id="sec-gtkbox">
<title><classname role="widget">GtkBox</classname></title>
<para>
<classname role="widget">GtkBox</classname> は, ウィジェットの行数
(<classname role="widget">GtkHBox</classname>) または, 列数
(<classname role="widget">GtkVBox</classname>) を管理します。
<classname role="widget">GtkHBox</classname>によって, 全ウィジェットが
同じ高さを割り当てられます。ボックスのジョブは, ウィジェット間に
利用可能な幅を提供することです。
<classname role="widget">GtkHBox</classname>は, ウィジェット間での相違
("スペーシング(spacing)"といわれます)を残すために有効な幅をオプション
的に使用します。
<classname role="widget">GtkVBox</classname>も同じですが, 対する方向に
関してです。(すなわち, 幅よりもむしろ有効な高さを提供します。)
<classname role="widget">GtkBox</classname>は, 抽象的基本クラスです。
<classname role="widget">GtkVBox</classname>と
<classname role="widget">GtkHBox</classname>は, 主として
そのインタフェースを通して完全な状態で使用することができます。
ボックスは, 最も役立つコンテナウィジェットです。
</para>
<para>
<classname role="widget">GtkBox</classname>を作成するには,
<xref role="flref" linkend="fl-hboxconstruct">や
<xref role="flref" linkend="fl-vboxconstruct">に示されている, 構造の
一方を使用します。ボックスの構造関数は, 2つのパラメータをとります。
<structname role="C">TRUE</structname>ならば<structname
role="C">homogeneous</structname>は, ボックスの全ての子が同じ量の
スペースを割り当てられるということを意味します。<structname
role="C">spacing</structname>は, 各子の間でスペースの量を指定します。
ボックス作成後, スペーシングやトグルの均一性を変更する機能もあります。
</para>
<figure role="functionlist" id="fl-hboxconstruct">
<title id="fl-hboxconstruct.title"><classname
role="widget">GtkHBox</classname> コンストラクタ</title><funcsynopsis
role="functionlist" id="fl-hboxconstruct.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkhbox.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>GtkWidget* <function>gtk_hbox_new</function></funcdef>
<paramdef>gboolean
<parameter>homogeneous</parameter></paramdef><paramdef>gint
<parameter>spacing</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<figure role="functionlist" id="fl-vboxconstruct">
<title id="fl-vboxconstruct.title"><classname
role="widget">GtkVBox</classname> コンストラクタ</title><funcsynopsis
role="functionlist" id="fl-vboxconstruct.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkvbox.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>GtkWidget* <function>gtk_vbox_new</function></funcdef>
<paramdef>gboolean
<parameter>homogeneous</parameter></paramdef><paramdef>gint
<parameter>spacing</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
<classname role="widget">GtkBox</classname>に子を追加する2つの基本的
関数があります。<xref role="flref" linkend="fl-boxpack">に示されて
います。
</para>
<figure role="functionlist" id="fl-boxpack">
<title id="fl-boxpack.title">パック <classname
role="widget">GtkBox</classname></title><funcsynopsis
role="functionlist" id="fl-boxpack.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkbox.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void <function>gtk_box_pack_start</function></funcdef>
<paramdef>GtkBox*
<parameter>box</parameter></paramdef><paramdef>GtkWidget*
<parameter>child</parameter></paramdef><paramdef>gboolean
<parameter>expand</parameter></paramdef><paramdef>gboolean
<parameter>fill</parameter></paramdef><paramdef>gint
<parameter>padding</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_box_pack_end</function></funcdef>
<paramdef>GtkBox*
<parameter>box</parameter></paramdef><paramdef>GtkWidget*
<parameter>child</parameter></paramdef><paramdef>gboolean
<parameter>expand</parameter></paramdef><paramdef>gboolean
<parameter>fill</parameter></paramdef><paramdef>gint
<parameter>padding</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
ボックスは, ウィジェットの2つのセットを含むことができます。最初の
セットは, ボックスの "前方"(上端または左)にパック(pack)され,
もう一方は"後方"(下端または右)で行われます。もしボックスの前方に
3つのウィジェットをパックする場合は, パックする最初のウィジェットが
最上段もしくは最も左に現れます。その次がそれに続き, 3つ目はボックス
の中央に最も近いところに現れます。そして3つのウィジェットを
同じボックスの後方にパックすると, 最初のウィジェットは最下段もしくは
最も右側に現れ,次がそれに続き, 3つ目は中央に近いところに現れます。
パックされた全 6ウィジェットを用いて, 上端/左から下端/右への
順序が, 1, 2, 3, 3, 2, 1 となります。
<xref linkend="fig-packstartend"> では,
<classname role="widget">GtkVBox</classname>を用いたこの状態を
示しています。パックの順序は, 各ボックスの後方内でのみ重要です。
すなわち, 同じ結果で前方にパックしたり, 後方にパックすることを
置換できています。
</para>
<figure float="1" id="fig-packstartend">
<title><classname role="widget">GtkVBox</classname>
にパックされたボタン</title> <graphic
fileref="figures/packstartend" format="png"></graphic> </figure><sect3
id="fig-gtk-gtklayout"> <title><classname role="widget">GtkBox
</classname> レイアウトの詳細</title>
<para>
パックは, 3つのパラメータの影響を受けます。それらは, 前方及び後方の
パックに対しても同様です。これらのパラメータが持つ意味は多少複雑
です。
というのは, <structname role="C">homogeneous</structname>を使って
ボックスの設定をし, そして互いが相互作用を行うからです。
</para>
<para>
これは, <classname role="widget">GtkBox</classname>が"注目している"
方角(<classname role="widget">GtkHBox</classname>では幅,
<classname role="widget">GtkVBox</classname>では高さです。)
に対するサイズ要求をどのように計算しているかです。
</para>
<orderedlist>
<listitem>
<para>
各子のサイズ要求の総合が子のサイズ要求と見なされ, さらに2回
<structname role="C">padding</structname>値が子をパックするのに
用いられます。子の<structname role="C">padding</structname>は,
その両サイドにある空白の量です。手短にいうと, 子のサイズ =
(子ウィジェットのサイズ要求) + 2*(子パディング)です。
</para>
</listitem>
<listitem>
<para>
ボックスが均一(homogeneous)である場合, 全ボックスの基本サイズ
要求は,
最大の子のサイズ(要求 + パディング)に等しく, 子の数の倍です。
均一のボックスでは, 全ての子が最大の大きさを持つ子に等しく
なります。
</para>
</listitem>
<listitem>
<para>
ボックスが均一でない場合, 全ボックスの基本サイズ要求は,
それぞれの子のサイズ(要求 + パディング)の合計になります。
</para>
</listitem>
<listitem>
<para>
<structname role="C">spacing</structname>設定してあるボックス-幅
は, 子の間にどれくらいの空白を残すか決定します。
そのためこの値は, この数マイナス1で処理され, 基本サイズ要求を追加
します。<firstterm>スペーシング(spacing)</firstterm>が,
子に依存していない点に注意して下さい。
つまり子の間の空白であって,
<structname role="C">expand</structname>や
<structname role="C">fill</structname>パラメータには影響され
ません。一方, <firstterm>パディング(padding)</firstterm>は
それぞれの子のまわりの大きさのため, 子のパックしている
パラメータの影響を<emphasis>受けます</emphasis>。
</para>
</listitem>
<listitem>
<para>
全コンテナが"境界幅"を設定します。2回, 境界幅が要求に追加され,
両サイドに境界を表示します。そのため,
<classname role="widget">GtkBox</classname>で要求された全体的な
サイズは, (子サイズの総合) +
スペーシング*(子の数 - 1) + 2*(境界幅) です。
</para>
</listitem>
</orderedlist>
<para>
サイズ要求を計算し, それが親コンテナに伝わると
<classname role="widget">GtkBox</classname>はそのサイズ配置を
受け取り, 次のように子の間に伝わります。
</para>
<orderedlist>
<listitem>
<para>
境界幅と内的子スペーシングに対する十分なスペースが, 割り当て
から取られます。残りが子自体に有効なスペースです。
このスペースが, 2つ, すなわち実際に子(子の要求とパディング)
が要求する量と"余分値(extra)"に
分割されます。余分値 = (配置サイズ) - (子のサイズ総合) です。
</para>
</listitem>
<listitem>
<para>
ボックスが均一でないならば, "余分"スペースは
<structname role="C">TRUE</structname>に設定された
<structname role="C">expand</structname>パラメータを使って,
それらの子の間で分割されます。これらの子は, 有効なスペースに
適応しながら拡大します。子がないと拡張せず, 余分値は
ボックスの中央で前方パックウィジェットと後方パックウィジェットの
間にスペースを追加するのに使用されます。
</para>
</listitem>
<listitem>
<para>
ボックスが均一の場合は, 余分値は必要に応じて割り当てられます。
これらの子は, より多くのスペースを要求したので余分値は少なく,
そのため誰もがスペースを同量で終了します。
<structname role="C">expand</structname>パラメータは, 均一
ボックスのため無視されます。—余分値は, 全ての子に分配され,
拡張可能なものだけということはありません。
</para>
</listitem>
<listitem>
<para>
子が余分なスペースを得ると, 2つの可能性が生じます。
子のまわりにさらにパディングが追加されるか, もしくは
子ウィジェット自体が拡張するかです。
<structname role="C">fill</structname> パラメータは,
どちらが生じるかを決定します。
<structname role="C">TRUE</structname>ならば, 子ウィジェットが
スペースに広がり—つまり, 全スペースが子の配置になります。
<structname role="C">fill</structname> が <structname
role="C">FALSE</structname>ならば, 子のパディングがスペースで
行われ, 子は要求されたスペースのみ配置されます。
<structname role="C">fill</structname> は,
<structname role="C">expand</structname>が
<structname role="C">FALSE</structname>に設定されていたとしても
影響は受けず, ボックスは均一にならないという点に注意して下さい。
というのは, 子が決して余分なスペースを受け入れないからです。
</para>
</listitem>
</orderedlist>
<para>
しかしながら, それら全てに関して考案したいと思う人がいるでしょうか。
幸いにも,
いくつかの共通した仕様パターンがあります。そのためウィジェットの
使い方といった多数変数的方程式を解く必要はないのです。
GTK+チュートリアルの著者は, 特に発生する5つの場合に要約しています。
ここではその先例に倣いましょう。
</para>
</sect3>
<sect3 id="sec-gtk-boxpack">
<title>非均一なボックスパッキングパターン</title>
<para>
非均一(non-homogeneous)ボックスをパックする3つの面白い方法が
あります。最初の方法は,
もとのサイズで全ウィジェットをボックスの後方にパックすることが
できます。これは<structname role="C">expand</structname>パラメータを
<structname role="C">FALSE</structname>に設定するということです。
</para>
<programlisting>
gtk_box_pack_start(GTK_BOX(box),
child,
FALSE, FALSE, 0);
</programlisting>
<para>
結果は, <xref linkend="fig-packnonhomonoexpandnofill">のように
なります。 <structname role="C">expand</structname> パラメータは,
この場合重要となる唯一のパラメータです。子が余分なスペースを
全く受け取っていないので,
例え<structname role="C">fill</structname>が
<structname role="C">TRUE</structname>であったとしても
埋めることはできないでしょう。
</para>
<figure float="1" id="fig-packnonhomonoexpandnofill">
<title><structname role="C">expand = FALSE</structname>
時の非均一 <graphic
fileref="figures/packnonhomonoexpandnofill" format="png"></graphic>
</figure><para> 次の方法では, ボックス中でウィジェットを配置する
ことができます。<xref linkend="fig-packnonhomoexpandnofill">
で示されるようにサイズはもとの状態です。これは,
<structname role="C">expand</structname>パラメータが<structname
role="C">TRUE</structname>ということです。</para>
<programlisting>
gtk_box_pack_start(GTK_BOX(box),
child,
TRUE, FALSE, 0);
</programlisting>
<figure float="1" id="fig-packnonhomoexpandnofill">
<title><structname role="C">expand = TRUE</structname>
かつ <structname role="C">fill = FALSE</structname>時の
非均一</title> <graphic
fileref="figures/packnonhomoexpandnofill" format="png"></graphic>
</figure><para> 最後の方法では,
<structname role="C">fill</structname>パラメータも
<structname role="C">TRUE</structname>に設定し,
ウィジェット(より大きい子に更に多くのスペースを持たせながら)で
ボックスを埋めることができます。</para>
<programlisting>
gtk_box_pack_start(GTK_BOX(box),
child,
TRUE, TRUE, 0);
</programlisting>
<para>
この構成は, <xref linkend="fig-packnonhomoexpandfill">に
示されています。
</para>
<figure float="1" id="fig-packnonhomoexpandfill">
<title><structname role="C">expand = TRUE</structname>
かつ <structname role="C">fill = TRUE</structname>
時の非均一</title> <graphic
fileref="figures/packnonhomoexpandfill" format="png"></graphic>
</figure>
</sect3>
<sect3 id="sec-gtk-hboxpack">
<title>均一ボックスパッキングパターン</title>
<para>
均一ボックスに関して面白いパックの方法は, 2つだけです。
<structname role="C">expand</structname>パラメータが, 均一ボックスに
対しては無関係であることを思い出して下さい。そのため,
<structname role="C">fill</structname>パラメータ設定に対応するのは
2つの場合です。
</para>
<para>
<structname role="C">fill</structname> が <structname
role="C">FALSE</structname>ならば,
<xref linkend="fig-packhomonofill">のようになります。
ボックスが論理的に3つの均等性を持ってに分かれている点に注意して
下さい。ただし, 最も大きな子ウィジェットのみ全体のスペースを使用
しています。その他は, 領域のそれそれの1/3を埋めるために詰められて
います。<structname role="C">fill</structname>が
<structname role="C">TRUE</structname>ならば
<xref linkend="fig-packhomofill">のようになり,
全ウィジェットが同じサイズになります。
</para>
<figure float="1" id="fig-packhomonofill">
<title><structname role="C">fill = FALSE</structname>時の
均一<graphic fileref="figures/packhomonofill"
format="png"></graphic> </figure><figure float="1"
id="fig-packhomofill"> <title><structname role="C">fill = TRUE
</structname>時の均一</title> <graphic
fileref="figures/packhomofill" format="png"></graphic>
</figure>
</sect3>
<sect3 id="sec-gtk-boxpacksum">
<title>ボックスパッキングの要約</title>
<para>
<xref linkend="fig-allpack"> では, 全5つのボックスパッキング
テクニックをまとめて紹介しています。 (それらは,
<structname role="C">fill</structname>を<structname
role="C">TRUE</structname>に設定し, 2つのピクセルの内部的子
スペーシングを使って均一<classname role="widget">GtkVBox</classname>
にパックされています。)これが, 互いに関連して影響を与えます。
同時に, <structname role="C">padding</structname>及び
<structname role="C">spacing</structname>パラメータを使って
ウィジェット間の空白量を増加したり, 減少させたりできるということを
心に留めておいて下さい。しかしながら, 一貫性にかけるスペーシングを
用いると体裁の悪いレイアウトは簡単に作成できます。—
ウィジェットを"一並列"にし, 一貫性あるスペースを保つのが良い
考えでしょう。
</para>
<figure float="1" id="fig-allpack">
<title>ボックスをパックする全5手段</title>
<graphic fileref="figures/allpack" format="png"></graphic>
</figure>
<para>
最後の重量点は, <structname role="C">expand</structname>及び
<structname role="C">fill</structname>パラメータがボックスのサイズ
配置がその要求よりも大きいときのみ関連してくるという点です。
つまり, これらのパラメータがどのように
<emphasis>余分</emphasis>スペースを割り当てるかを決定します。
とりわけ, 余分スペースはユーザがウィンドウをデフォルトの大きさよりも
大きくさせると現れます。それゆえ, ボックスが正しくパックされている
か確信するには, 常にサイズ変更を試みるべきでしょう。
correctly.
</para>
</sect3>
</sect2>
<sect2 id="sec-gtktable">
<title><classname role="widget">Gtkテーブル</classname></title>
<para>
次に, 一般的なレイアウトコンテナは<classname role="widget">
GtkTable</classname>です。<classname role="widget">GtkTable</classname>
は, 領域をセルに分割します。各子ウィジェットを1つ以上のセルから
成り立つ長方形に割り当てることができます。
<classname role="widget">GtkTable</classname>を1枚のグラフ用紙と
考えることもできます。(更に柔軟性をもつと—グリッドラインは,
そうなることはあり得ないかもしれませんが等間隔である必要はありません。)
</para>
<para>
<classname role="widget">GtkTable</classname> は, 通常の
コンストラクタ, そしてそれに付随する子への機能に備わっています。
これは, <xref role="flref" linkend="fl-gtktable">に示されています。
テーブルが作成されると, 使用する予定のセル数を指定します。これは,
単に効率向上のためです。カレント領域の外側のセルに子を配置すると
自動的にテーブルが変化します。ボックスのように, テーブルは均一で
あったり, そうでなかったりします。
</para>
<figure role="functionlist" id="fl-gtktable">
<title id="fl-gtktable.title"><classname
role="widget">GtkTable</classname></title><funcsynopsis
role="functionlist" id="fl-gtktable.synopsis">
<funcsynopsisinfo>
#include <gtk/gtktable.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>GtkWidget* <function>gtk_table_new</function></funcdef>
<paramdef>guint
<parameter>rows</parameter></paramdef><paramdef>guint
<parameter>columns</parameter></paramdef><paramdef>gboolean
<parameter>homogeneous</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>GtkWidget* <function>gtk_table_attach</function></funcdef>
<paramdef>GtkTable*
<parameter>table</parameter></paramdef><paramdef>GtkWidget*
<parameter>child</parameter></paramdef><paramdef>guint
<parameter>left_side</parameter></paramdef><paramdef>guint
<parameter>right_side</parameter></paramdef><paramdef>guint
<parameter>top_side</parameter></paramdef><paramdef>guint
<parameter>bottom_side</parameter></paramdef><paramdef>GtkAttachOptions
<parameter>xoptions</parameter></paramdef><paramdef>GtkAttachOptions
<parameter>yoptions</parameter></paramdef><paramdef>guint
<parameter>xpadding</parameter></paramdef><paramdef>guint
<parameter>ypadding</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
<function>gtk_table_attach()</function>の最初の2つの引数は, テーブルと
そのテーブルに置かれる子です。次の4つは, どのグリッドラインが
子のボックス境界を形成するかを指定しています。グリッドラインは,
テーブルの最上段左(北西)の角から数えられ, 0から始まります。そのため
2, 3テーブルは, 垂直ライン0, 1, 2, で, 水平ラインは0, 1, 2, 3,
です。最後の2つの引数は, 子の左右方面 (<structname role="C">xpadding
</structname>)及び, 上下方向 (<structname role="C">ypadding
</structname>)に置かれるパディングの量です。これは, ボックスでの
パディングに類似します。
</para>
<para>
<structname role="C">GtkAttachOptions</structname>引数は, 多少説明を
要します。以下は, とりうる値の要点です。値はビットマスクなので, 1以上は
or-ing形式でそれらを一緒に指定することができます。
</para>
<itemizedlist>
<listitem>
<para>
<structname role="C">GTK_EXPAND</structname> は, テーブルのこの部分
が有効なスペースの適合に拡張するよう指定します。
パッキングボックスの
<structname role="C">expand</structname>オプションみたいです。
</para>
</listitem>
<listitem>
<para>
<structname role="C">GTK_FILL</structname> は, 子ウィジェットが
有効なスペースを埋めるために拡張するよう指定します。重要なのは,
<structname role="C">GTK_EXPAND</structname>が設定されている
ときのみです。
というのは,<structname role="C">GTK_EXPAND</structname>
が, 余分なスペースの存在を許すからです。
</para>
</listitem>
<listitem>
<para>
<structname role="C">GTK_SHRINK</structname> は, 子ウィジェットの
サイズ要求に対してスペースが十分でない場合どうするかを決定します。
<structname role="C">GTK_SHRINK</structname> が設定されていると,
子には有効なスペースに関係してより小さな割り当てが与えられます。
—すなわち, テーブルが子を縮小するのです。
設定されていない場合, 子には要求されているサイズが与えられます。
これは, テーブル内で子が重なる可能性があり, 子がテーブルの端で
"切り落とされる"でしょう。(というのは, それらがテーブルの
<structname role="C">GdkWindow</structname>の外側に描き出そうと
するからです。)
</para>
</listitem>
</itemizedlist>
<para>
特別な子のまわりのパディングに加え, 行数と列数の間にスペーシングを
設定することも可能です。"スペーシング"と"パディング"では,
テーブルとボックスに関して同じような意味合いを持ちます。
有効な<classname role="widget">GtkTable</classname>関数の
完全なリストは, <filename role="header">gtk/gtktable.h</filename>を
ご覧下さい。
</para>
<sect3 id="sec-gtk-gtktable">
<title><classname role="widget">GtkTable</classname> の例</title>
<para>
以下のコードは, 4つのセルと3つの子で構成されるテーブルを作成します。
1つの子が2つのセルにあたります。子は異なるパラメータを用いて
パックされています。
</para>
<programlisting>
GtkWidget* window;
GtkWidget* button;
GtkWidget* container;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
container = gtk_table_new(2, 2, FALSE);
gtk_container_add(GTK_CONTAINER(window), container);
gtk_window_set_title(GTK_WINDOW(window), "Table Attaching");
gtk_container_set_border_width(GTK_CONTAINER(container), 10);
/* これは, 実際のコードではよくない使い方です。ただし,
* ウィンドウのサイズ変更を行い, 具体的な説明になるでしょう。
*/
gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(delete_event_cb),
NULL);
button = gtk_button_new_with_label("1. Doesn't shrink\nor expand");
gtk_table_attach(GTK_TABLE(container),
button,
0, 1,
0, 1,
GTK_FILL,
GTK_FILL,
0,
0);
button = gtk_button_new_with_label("2. Expands and shrinks\nvertically");
gtk_table_attach(GTK_TABLE(container),
button,
0, 1,
1, 2,
GTK_FILL,
GTK_FILL | GTK_EXPAND | GTK_SHRINK,
0,
0);
button = gtk_button_new_with_label("3. Expands and shrinks\nin both directions");
gtk_table_attach(GTK_TABLE(container),
button,
1, 2,
0, 2,
GTK_FILL | GTK_EXPAND | GTK_SHRINK,
GTK_FILL | GTK_EXPAND | GTK_SHRINK,
0,
0);
</programlisting>
<para>
ウィンドウの大きさを変更して, 結果として得られるテーブルに注目
するのは効果的です。まず, 子がどのように取り付けられるかの簡単な
要約です。
</para>
<orderedlist>
<listitem>
<para>
最初の子は, 常にその要求されたサイズを受け取ります。
拡張したり, 縮小したりはしません。
</para>
</listitem>
<listitem>
<para>
2番目の子は, Y 方向にのみ拡張し, 縮小します。
</para>
</listitem>
<listitem>
<para>
3番目の子は, 両方向に拡張, 縮小します。
</para>
</listitem>
</orderedlist>
<para>
ウィンドウのもとのサイズは, <xref linkend="fig-tablenatural">に
示されています。セル内部にウィジェットが要求している以上の
スペースが与えられている点に注意して下さい。というのは, テーブルの
セルは, 一列でなければならないからです。(ラベルのあるボタンは,
全ラベルを表示できる程度のスペースのみ要求するという点を
思い出して下さい。) <structname role="C">GTK_FILL</structname>の
フラグは, 空白をウィジェットのまわりにパディングさせたままにせず,
<classname role="widget">GtkTable</classname>に余分なスペースを
ウィジェット自体に割り当てさせます。
</para>
<figure float="1" id="fig-tablenatural">
<title>サイズ変更前の<structname role="C">GtkTable</structname></title>
<graphic fileref="figures/tablenatural" format="png"></graphic>
</figure>
<para>
それでは, ユーザが垂直方向にウィンドウを拡張する場合をみてみま
しょう。余分なスペースは, Y方向に向けられている<structname
role="C">GTK_EXPAND</structname>を用いてウィジェットに与えられます。
—つまり, ウィジェット2と3です。—左上角の
ウィジェットは, 変化していません。
<xref linkend="fig-tablevertresize">は, この状態を示しています。
</para>
<figure float="1" id="fig-tablevertresize">
<title>垂直方向ウィンドウ拡張後の
<structname role="C">GtkTable</structname></title>
<graphic fileref="figures/tablevertresize" format="png"></graphic>
</figure>
<para>
次に, ユーザが水平方向にウィンドウを拡張する場合をみてみましょう。
3の子ウィジェットのみが, 水平方向に拡張できます。
<xref linkend="fig-tablehorizresize"> は, これを示しています。
</para>
<figure float="1" id="fig-tablehorizresize">
<title>水平方向ウィンドウ拡張後の
<structname role="C">GtkTable</structname></title>
<graphic fileref="figures/tablehorizresize" format="png"></graphic>
</figure>
<para>
<xref linkend="fig-tablevertshrink">は, ユーザが垂直方向にテーブルを
縮小した場合です。そのため, 全ウィジェットに対するサイズ要求に
見合った垂直方向スペースがありません。2の子ウィジェットは, 1の子
ウィジェットが必要とする全垂直方向のスペースを確保しているため,
配分が少なくなっています。
</para>
<figure float="1" id="fig-tablevertshrink">
<title>垂直方向ウィンドウ縮小後の
<structname role="C">GtkTable</structname> </title>
<graphic fileref="figures/tablevertshrink" format="png"></graphic>
</figure>
<para>
最後に, <xref linkend="fig-tablehorizshrink">はユーザが水平方向に
テーブルを縮小した場合です。3の子ウィジェットは, この状態で縦方向に
縮小されています。
</para>
<figure float="1" id="fig-tablehorizshrink">
<title>水平方向ウィンドウ縮小後の
<structname role="C">GtkTable</structname> </title>
<graphic fileref="figures/tablehorizshrink" format="png"></graphic>
</figure>
<para>
レイアウトを考える際は, ちょうど思っていたとおり(sane)の
ことが起こっているか確認するためにも, このようにウィンドウの
サイズ変更を試みるのも良いでしょう。"sane"の定義は, レイアウトに
配置した正確なウィジェットによって変化します。
</para>
</sect3>
<sect3 id="sec-gtk-attachdef">
<title><function>gtk_table_attach_defaults()</function>の使用</title>
<para>
<function>gtk_table_attach()</function>には多少面倒な点がありますが,
<function>gtk_table_attach_defaults()</function>のような単純な
関数も存在します。それについては,
<xref role="flref" linkend="fl-attachdefaults">に示されています。
この関数は, オプション<structname role="C">GTK_EXPAND</structname>
及び<structname role="C">GTK_FILL</structname>のある子を添え付け,
パディングはしません。
</para>
<para>
タイプを保存するためには, いつも
<function>gtk_table_attach_defaults()</function>を使おうと
考えるかもしれませんが, 実際には用いるべきではありません。事実,
滅多に使われないといった方が公平な見方でしょう。この関数は,
デフォルトが希望の設定に正確になっているときのみ役立ちます。
大概において, ウィンドウをサイズ変更し, 実際に正しい振る舞いを
得るためにはテーブルに備えたパラメータを注意して取り扱う必要が
あります。レイアウトがきちんと構成されているか確認するには, 常に
サイズ変更を試みて下さい。
</para>
<figure role="functionlist" id="fl-attachdefaults">
<title id="fl-attachdefaults.title">デフォルトでの添付
</title><funcsynopsis role="functionlist"
id="fl-attachdefaults.synopsis">
<funcsynopsisinfo>
#include <gtk/gtktable.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>GtkWidget*
<function>gtk_table_attach_defaults</function></funcdef>
<paramdef>GtkTable*
<parameter>table</parameter></paramdef><paramdef>GtkWidget*
<parameter>child</parameter></paramdef><paramdef>guint
<parameter>left_side</parameter></paramdef><paramdef>guint
<parameter>right_side</parameter></paramdef><paramdef>guint
<parameter>top_side</parameter></paramdef><paramdef>guint
<parameter>bottom_side</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect3>
</sect2>
<sect2 id="sec-gtk-otherlay">
<title>その他のウィジェットレイアウト</title>
<para>
ボックスとテーブルは, とりわけ最も一般的に用いられるレイアウト
ウィジェットです。しかしながら, 特別な状況に置けるその他の用法
もあります。
</para>
<itemizedlist>
<listitem>
<para>
<classname role="widget">GtkButtonBox</classname> は,
ダイアログの"動作領域"に適した特殊なボックスです。
</para>
</listitem>
<listitem>
<para>
<classname role="widget">GtkPacker</classname> は,
<application>Tk</application>-形式 パッキングをサポート
しているため, <application>Tk</application>になれている方には
便利です。
</para>
</listitem>
<listitem>
<para>
<classname role="widget">GtkLayout</classname> は,
無数のスクロール領域を提供します。通常, GTK+のスクロール領域は,
30,000ピクセル以上に制限されています。というのは,
これがXウィンドウの最大サイズのためです。
</para>
</listitem>
<listitem>
<para>
<classname role="widget">GtkFixed</classname> は,
固定座標に手動でウィジェットを配置できるようにします。
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="sec-gtk-manual">
<title>手動で効果的なレイアウト</title>
<para>
手動でGTK+のジオメトリ管理を書き換えることが可能です。しかしながら,
時間的にみて95% が良い考えとはいえないでしょう。なぜなら, GTK+の
ジオメトリは本質的にユーザの好むジオメトリであり,テーマによって決定
され, トップレベルのウィンドウのサイズ変更を行います。手動で何かを
行いたい場合は, おそらく不適切なレイアウトコンテナを用いているか,
もしくは本当にカスタムコンテナウィジェットを書かなければならないか
でしょう。
</para>
<para>
<xref role="flref" linkend="fl-setu">に示されるような関数を用いて,
ウィジェットにサイズと位置を強制することもできます。
しかしながら, その使用が理想的であることはまれです。特に,
<function>gtk_widget_set_usize()</function>はトップレベルのウィンドウ
デフォルトサイズ設定に用いられるべきではありません。通常,
アプリケーションの動作状態を保存し, 更にそれを再度保存したり, ユーザが
コマンドラインでウィンドウのジオメトリを指定したりするため,
ウィンドウのサイズを設定する必要があります。残念なことに,
<function>gtk_widget_set_usize()</function>を用いると, ユーザは
ウィンドウを縮小できず, 嫌がらせのメールが届くことになる
かもしれません。サイズを強制するのではなく,
<function>gtk_window_set_default_size()</function>を用いて初期サイズ
を指定するには, <xref role="flref" linkend="fl-defaultsize">
をご覧下さい。<function>gtk_widget_set_usize()</function> は,
非トップレベルウィジェットに対してはあまり適していません。
ほとんどの場合, 適切なレイアウトウィジェットを使ってよりよいものを
作成できるでしょう。
</para>
<para>
<function>gtk_widget_set_uposition()</function> は, トップレベル
ウィジェットに対してのみ役立ちます。というのは, 他のウィジェットに
対しては意味を持たないからです。
<application role="tt">--geometry</application>コマンドライン引数の
添付は主として用いられます。
</para>
<para>
これらの3つの全関数が, <structname role="C">x</structname>,
<structname role="C">y</structname>, <structname
role="C">width</structname>, または<structname role="C">height
</structname>引数に対し<structname role="C">-1</structname>を
受け入れます。関数は, どの<structname role="C">-1</structname>引数も
無視するので, これは 2つの引数のうち1つのみを設定でき,
他方にデフォルト値を残すということです。
</para>
<figure role="functionlist" id="fl-setu">
<title id="fl-setu.title">強制配置</title><funcsynopsis
role="functionlist" id="fl-setu.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void
<function>gtk_widget_set_uposition</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef><paramdef>gint
<parameter>x</parameter></paramdef><paramdef>gint
<parameter>y</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_set_usize</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef><paramdef>gint
<parameter>width</parameter></paramdef><paramdef>gint
<parameter>height</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<figure role="functionlist" id="fl-defaultsize">
<title id="fl-defaultsize.title">デフォルトウィンドウサイズ
</title><funcsynopsis role="functionlist"
id="fl-defaultsize.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwindow.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void
<function>gtk_window_set_default_size</function></funcdef>
<paramdef>GtkWindow*
<parameter>window</parameter></paramdef><paramdef>gint
<parameter>width</parameter></paramdef><paramdef>gint
<parameter>height</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
</sect1>
<sect1 id="sec-gtk-widgetconcpt">
<title>ウィジェットの概念</title>
<para>
この章では, ウィジェット全体にあてはまる概念についてです。メモリ管理や
ウィジェットのある特別な状態についても含んでいます。"概念"に関する章で
すが, 概念は本書の後半で触れる実際的な内容に対して非常に重要です。
</para>
<sect2 id="widgetlifecycle">
<title>ウィジェットライフサイクル</title>
<para>
ウィジェットリソースとメモリ管理は, 大部分が自動です。しかしながら,
より複雑なことを行う場合には,心に留めておいていただきたい一種の
"決まり事"があります。
</para>
<figure role="functionlist" id="fl-widgetdestroy">
<title id="fl-widgetdestroy.title">Widgetの
破棄</title><funcsynopsis role="functionlist"
id="fl-widgetdestroy.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void <function>gtk_widget_destroy</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
ウィジェットは, <function>gtk_widget_destroy()</function>がコール
されると破棄されます。(<xref role="flref" linkend="fl-widgetdestroy">
に示されています。)ウィジェットの破棄によってそれに関連したメモリや
その他のリソースが解放されます。ウィジェットがコンテナの内部の場合,
破棄される以前にコンテナから自動的に取り除かれます。
<function>gtk_widget_destroy()</function>は, 単に
<function>gtk_object_destroy()</function>の別称にすぎないと注目
するのは一理あります。<structname role="C">GtkObject</structname>
は"仮想消去関数"を備えているので,
<function>gtk_object_destroy()</function>は, 常に正当な動作を行います。
</para>
<para>
内部的に, 全ウィジェットに対してリファレンスカウント(reference count)
が用意されています。
(実際, 全ての<structname role="C">GtkObject</structname>に対してです。)
オブジェクトは, そのライフをたとえまだリファレンスしていないとしても,
そのリファレンスカウントを1で始めます。この段階で, オブジェクトは
<firstterm>フローティング(floating)</firstterm>が言い渡され,
そのようにフラグがたてられます。オブジェクトの初期リファレンスを
削除することは可能です。これをフローティングオブジェクトの
<firstterm>シンキング(sinking)</firstterm>といわれています。
フローティングリファレンス(floating reference)が一つだけの場合は,
オブジェクトは破棄されるでしょう。
</para>
<para>
コンテナは, 追加されたどのようなウィジェットに対してもまずリファレンス
を行い, それからシンク(sink)します。ウィジェットをシンクすると,
コンテナはリソース管理目的のため"所有権限を取り"ます。そのため,
ウィジェットのリファレンスカウントは 1 のままですが, オブジェクトは
もはやフローティングのようにフラグをたてられません。ウィジェットが,
コンテナ—または, 破棄されたコンテナ—から削除されると,
リファレンスカウントは 0 になります。オブジェクトのリファレンス
カウントが 0 になると, 破棄されます。
</para>
<para>
実際には, トップレベルウィジェットを破棄しなければならないだけの
ことで, 内部のコンテナになる全てのウィジェットがそのコンテナに沿った
形で破棄されます。
</para>
<para>
しかしながら, ここにひとつの危険性があります。時に, コンテナから
ウィジェットを取り除きたい場合, 恐らくインタフェースの要素は
オプション的であったり, または特定の環境下でのみ現れます。
ウィジェットを
取り除く際(<function>gtk_container_remove()</function>を使って),
リファレンスされず, そのリファレンスカウントは 0 になり, 破棄
されます。この状況を避けるには, ウィジェットを取り除く前に,
リファレンスを追加しなければなりません。
<xref role="flref" linkend="fl-refcounts">
は, リファレンスカウントの処理を行う関数です。
</para>
<figure role="functionlist" id="fl-refcounts">
<title id="fl-refcounts.title">リファレンスカウント</title>
<funcsynopsis role="functionlist" id="fl-refcounts.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkobject.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void <function>gtk_object_ref</function></funcdef>
<paramdef>GtkObject*
<parameter>object</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_object_unref</function></funcdef>
<paramdef>GtkObject*
<parameter>object</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_object_sink</function></funcdef>
<paramdef>GtkObject*
<parameter>object</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
<function>gtk_object_ref()</function> 及び
<function>gtk_object_unref()</function> は, ウィジェット
(<function>gtk_widget_ref()</function>, 等。) 特有の相違点があります。
しかるに, オブジェクトやウィジェットのバージョンは, ほぼ同義です。
ウィジェット
特有のバージョンは, GTK+の旧バージョンから引き継いでいます。
</para>
<para>
そのため, コンテナからウィジェットを安全に取り除く際, 次のように
できます。
</para>
<programlisting>
gtk_widget_ref(widget);
gtk_container_remove(container, widget);
</programlisting>
<para>
ウィジェットは現在 1リファレンスで, コードで保たれています。
ある場合には, ウィジェットを破棄するためにリファレンスを解放する必要が
あります。(例えば, 他のコンテナにウィジェットを再追加した後等が
考えられます。)
</para>
<para>
コンテナからウィジェットを取り除くとことは, 希である点に目を付ける
価値はあります。通常, 単に<function>gtk_widget_hide()</function>を
使って,
ウィジェットを隠し, その後<function>gtk_widget_show()</function>を
用いた方が確実です。
</para>
<para>
<function>gtk_object_sink()</function> は, オブジェクトの主"所有者"で
あることを期待するとき, ほぼ排他的にウィジェットを実装するのにに用いら
れます。オブジェクトが "フローティング"していなければ,
<function>gtk_object_sink()</function>は影響を及ぼしません。
ウィジェットの所有権宣言は, 次のようにします。
</para>
<programlisting>
gtk_widget_ref(widget);
gtk_object_sink(GTK_OBJECT(widget));
</programlisting>
<para>
このコードでは, ウィジェットにリファレンスがひとつ追加されています。
ウィジェットが "フローティング"していると, リファレンスもまた1つ削除
されます。ウィジェットがフローティングしていない場合は,
<function>gtk_widget_sink()</function>は影響を及ぼしません。
</para>
<para>
詳細を理解することは重要です。というのは, 場合によって重大になる
からです。しかしながら, 大概は単純な 2, 3の規則でまかなえます。
</para>
<itemizedlist>
<listitem>
<para>
トップレベルウィジェットを使用し終わると, 破棄しなければならなり
ませんが, 子ウィジェットは自動的に破棄されます。
</para>
</listitem>
<listitem>
<para>
破棄せずにコンテナからウィジェットを取り除きたい場合,
まずウィジェットにリファレンスを追加します。
</para>
</listitem>
<listitem>
<para>
ウィジェットにリファレンスを追加する場合, ウィジェットを使用
し終えた際, 責任を持ってリファレンスを中止して下さい。
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="sec-realizingshowing">
<title>リアライズ, マッピング, 表示</title>
<para>
GTK+ を完全に理解するには, Xウィンドウシステムについての最小の理解が
必要です。本書では, ご自身がユーザレベルの知識をお持ちであることを
前提としています。— Xサーバが何であるか, Xがネットワーク透過
であり, ウィンドウマネージャが何を行うか等です。しかしながら,
プログラムを書く上で必要とされる更に2,3の詳細があります。
</para>
<para>
第1の詳細は, 特に重要です。Xウィンドウシステムは,
<firstterm>ウィンドウズ(windows)</firstterm>のツリーを維持しています。
この点において, "ウィンドウ" は, Xウィンドウに影響を与えますが,
<classname role="widget">GtkWindow</classname>には影響しません。
—<classname role="widget">GtkWindow</classname> は, GTK+特有の
概念で, アプリケーションのトップレベルXウィンドウに対するウィジェット
です。Xウィンドウは, <classname role="widget">GtkWindow</classname>で
表されれるユーザ可視的概念にある"ウィンドウ"ではありません。むしろ,
Xサーバで画面を分割するといった抽象的なものです。Xサーバで表示される
"バックグラウンド"は,
<firstterm>ルートウィンドウ(root window)</firstterm>です。
ルートウィンドウには, 親がありません。アプリケーションウィンドウは,
概してルートウィンドウに近い子です。大部分のウィンドウマネージャは,
ウィンドウのタイトルバー, その他の装飾を備えるためルートウィンドウの
子を作成し, ウィンドウ内部にアプリケーションを配置します。ウィンドウ
マネージャは, アプリケーションのウィンドウ上に全体的な制御を行います。
—つまり, 再配置し, 再度親となり, 自由にアイコン化できるのです。
アプリケーションウィンドウは, 順次サブウィンドウを含むことができます。
それらは, アプリケーションによって制御されます。GTK+は, Xディレクトリ
よりもGDKライブラリを使用する点に注意して下さい。GDKには,
<structname role="C">GdkWindow</structname>といわれる, 手軽な
Xウィンドウラッパ (X window wrapper) があります。
<structname role="C">GdkWindow</structname> と <classname
role="widget">GtkWindow</classname>を混同しないようにして下さい。
</para>
<para>
Xウィンドウ, または<structname role="C">GdkWindow</structname>は,
Xサーバに表示される画像の構造について暗示します。X は, ネットワーク
透過なので, ネットワーク交通量の削減に役立ちます。Xサーバは, 画面上
のウィンドウ表示, 隠見, 周囲の移動(適所にある子と親の関係を保ち
つつ), ウィンドウごとの基本的マウス動作のようなイベントの取得, 等
の仕方を知っています。<structname role="C">GdkWindow</structname>は,
画像を描くための基本的単位でもあります。
—全体的な"画面"を描くことは
できず, <structname role="C">GdkWindow</structname>に描かなければなり
ません。
</para>
<para>
大部分のGTK+ウィジェットに対応する<structname
role="C">GdkWindow</structname>が存在します。しかしながら,
<classname role="widget">GtkLabel</classname>のような例外もあります。
これらは, "非ウィンドウウィジェット" とされるため, 比較的軽量です。
<structname role="C">GdkWindow</structname>に関連しないウィジェットは,
その親の<structname role="C">GdkWindow</structname>に描かれます。
イベントの取得といった操作は,
<structname role="C">GdkWindow</structname>を要求します。そのため,
非ウィンドウウィジェット上では不可能です。
</para>
<para>
ウィジェットは, <structname role="C">GdkWindow</structname>に関する
いくつかの段階を経て渡されます。
</para>
<itemizedlist>
<listitem>
<para>
ウィジェットは, それに対応する
<structname role="C">GdkWindow</structname>が作成されると,
<firstterm>リアライズ(realize)</firstterm>されるといわれています。
ウィジェットは, <function>gtk_widget_realize()</function>で
リアライズし, <function>gtk_widget_unrealize()</function>で
アンリアライズ(unrealize)します。Xウィンドウには, 親が存在するので
ウィジェットがリアライズされると, その親もリアライズされます。
</para>
</listitem>
<listitem>
<para>
ウィジェットは, <function>gdk_window_show()</function>がその
<structname role="C">GdkWindow</structname>上でコールされると,
マッピングされます。これは, サーバが画面上にウィンドウを表示する
ように指令がいっているということです。明らかに,
<structname role="C">GdkWindow</structname>が存在していて,
ウィジェットがリアライズされていることを意味します。
</para>
</listitem>
<listitem>
<para>
ウィジェットは, 親がマッピングされると自動的にマッピングされる場合
<firstterm>可視的(visible)</firstterm>です。これは,
<function>gtk_widget_show()</function> がウィジェット上でコール
されるということです。ウィジェットは,
<function>gtk_widget_hide()</function>をコールすると非可視的に
なります。これは, 未決定の(pending)マップを範囲外とするか,
もしくはウィジェットをマッピングしないかのどちらかです。
(その<structname role="C">GdkWindow</structname>を隠します。)
トップレベルウィジェットには親が存在しないので,
それらが表示されるとすぐにマッピングされます。
</para>
</listitem>
</itemizedlist>
<para>
典型的なユーザコードでは, <function>gtk_widget_show()</function>の
コールが必要なだけです。これは, その親がリアライズされマッピング
されると直ちにリアライズし, マッピングするということです。
<function>gtk_widget_show()</function>は, 単にウィジェットを表示される
よう予定するだけであって, 直接の影響はないと理解しておくことは
重要です。これは, 特別な順序であってもウィジェット表示に注意する必要
はないということです。また, ウィジェットの<structname
role="C">GdkWindow</structname>に直ちにアクセスができないということ
です。 時には, <structname role="C">GdkWindow</structname>に
アクセスする必要があるでしょう。このような場合には, それを
作成するために<function>gtk_widget_realize()</function>を手動でのコール
を求めるかもしれません。<function>gtk_widget_realize()</function>は,
適合性を考慮して, 親ウィジェットもリアライズします。ところが.
<function>gtk_widget_realize()</function>を必要とするのは, 通常は
ありません。そういった場合は, 恐らく不適切な問題に近づきつつあるの
かもしれません。
</para>
<para>
ウィジェットの破棄は, 自動的にイベントの全逐次処理を逆戻りします。
再帰的に子ウィジェットを, それからウィジェット自体をアンリアライズ
します。
</para>
<para>
<xref role="flref" linkend="fl-showrealize"> は, この章で解説した
関数をまとめたものです。
</para>
<figure role="functionlist" id="fl-showrealize">
<title id="fl-showrealize.title">ウィジェットの
表示/リアライズ</title><funcsynopsis role="functionlist"
id="fl-showrealize.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void <function>gtk_widget_realize</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_unrealize</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_map</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_unmap</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_show</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_widget_hide</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
<xref role="mlref" linkend="ml-states"> は, この章で解説された動作
状態に必要とされるマクロをまとめたものです。
</para>
<figure role="macrolist" id="ml-states">
<title id="ml-states.title">ウィジェットの属性</title><funcsynopsis
role="macrolist" id="ml-states.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_NO_WINDOW</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_REALIZED</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_MAPPED</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_VISIBLE</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
<sect2 id="sec-gtk-otherwids">
<title>その他のウィジェット概念</title>
<para>
この章では, <classname role="widget">GtkWidget</classname>基本クラス
に関係するその他2,3の概念についてです。
<firstterm>応答(sensitivity)</firstterm>, <firstterm>フォーカス(focus)
</firstterm>, <firstterm>ウィジェット動作状態(widget states)
</firstterm>も含んでいます。
</para>
<sect3 id="sec-sensitivity">
<title>応答</title>
<para>
ウィジェットは, <firstterm>応答的(sensitive)</firstterm>または
<firstterm>非応答的(insensitive)</firstterm>になりえます。
非応答的ウィジェットは, 入力に反応しません。
(他のプラットフォームでは, "ゴースト化"
(ghosted), または "不活発"(inactive)とされています。)
</para>
<para>
<function>gtk_widget_set_sensitive()</function> (<xref role="flref"
linkend="fl-setsensitive">) は, ウィジェットの応答を変更します。
</para>
<figure role="functionlist" id="fl-setsensitive">
<title id="fl-setsensitive.title">応答変更
</title><funcsynopsis role="functionlist"
id="fl-setsensitive.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void
<function>gtk_widget_set_sensitive</function></funcdef>
<paramdef>GtkWidget*
<parameter>widget</parameter></paramdef><paramdef>gboolean
<parameter>setting</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
<para>
デフォルトでは, 応答は<structname role="C">TRUE</structname>に
設定されています。ウィジェットは, その全親ウィジェットが応答的の
場合, "実際に"応答的になります。
つまり, コンテナの応答を設定する事で,
コンテナ全体を(非)応答的ウィジェットにすることができます。
"現実的な"ウィジェットの応答は, 親の状態も含め
<function role="macro">GTK_WIDGET_IS_SENSITIVE()</function>マクロ
を用いて試行されます。ウィジェット自体の応答は, ウィジェットの親が
応答的かどうかを問題とするだけで,
<function role="macro">GTK_WIDGET_SENSITIVE()</function>を使って
要求することができます。これについては, <xref
role="mlref" linkend="ml-issensitive">に示されています。
</para>
<figure role="macrolist" id="ml-issensitive">
<title id="ml-issensitive.title">応答</title><funcsynopsis
role="macrolist" id="ml-issensitive.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_IS_SENSITIVE</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_SENSITIVE</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect3>
<sect3 id="sec-focuswidget">
<title>フォーカス</title>
<para>
各トップレベルウィンドウ内で, 1つのウィジェットが一度に
<firstterm>キーボードフォーカス(keyboard focus)</firstterm>を
受け取るかもしれません。
トップレベルウィンドウで受け取ったキーイベントは,
フォーカスされたウィジェットに転送されます。これは, 重要です。
というのは, キーボードで何かをタイプした場合の影響は, 一意的でなけ
ればならないからです。
—例えば, ひとつのテキストエントリフィールドのみの変更が
考えられますです。
</para>
<para>
大部分のウィジェットが, カレントフォーカスがあたっているとの
可視的な意図を
伝えます。デフォルトGTK+テーマを用いると, フォーカスされた
ウィジェットは, 概して手軽なブラックフレームに囲まれます。ユーザは,
ウィジェット間のフォーカスを矢印キーまたはタブキーを使って動かす
ことができます。フォーカスは, ユーザがウィジェットをクリックすると
そのウィジェットに移すこともできます。
</para>
<para>
フォーカスの概念は, キーボードナビゲーションにとって重要です。
例えば, フォーカスを得ていると, Enterまたはスペースをたたくことで
多くのウィジェットが"起動"します。例えば, タブキーを使ってボタン
間を移動し, スペースキーで選択することができます。
</para>
</sect3>
<sect3 id="sec-grabs">
<title>グラブ</title>
<para>
ウィジェットは, その他のウィジェットから離れてポインタやキーボードを
<firstterm>グラブ(grab)</firstterm>することができます。これは,
本質的にはウィジェットが"形式的"になるということです。入力は
ウィジェットのみに伝わり, フォーカスは別のウィジェットに変更
されません。入力をグラブする典型的な理由は, 形式的ダイアログの
作成です。ウィンドウがグラブすると, 他のウィンドウによる相互作用
は阻止されます。別途 GDK-レベルの "グラブ"がある点に注意して下さい。
GDK キーボード及びポインタグラブは, 広義基本Xサーバ上で
起こります。—つまり, その他のアプリケーションはキーボード
及びマウスのイベントを受け取ることができません。
ウィジェットグラブは, GTK+の概念です。同アプリケーション内で,
その他のウィジェットから離れてイベントをグラブするだけです。
</para>
</sect3>
<sect3 id="sec-gtk-def">
<title>デフォルト</title>
<para>
各ウィンドウには, 大概1つ<firstterm>デフォルト(default)</firstterm>
ウィジェットが存在するでしょう。
例えば, ダイアログは典型的なデフォルト
ボタンを持ちます。それは, Enterキーをユーザが押すと起動します。
</para>
</sect3>
<sect3 id="sec-widgetstates">
<title>ウィジェットの動作状態</title>
<para>
ウィジェットには, その外観を決定する
<firstterm>動作状態(states)</firstterm>が存在します。
</para>
<itemizedlist>
<listitem>
<para>
<firstterm>通常(Normal)</firstterm>: その文字が表すとおりです。
</para>
</listitem>
<listitem>
<para>
<firstterm>活発(Active)</firstterm>: 例として, ボタンが現在
押されている, またはチェックボックスがチェックされています。
</para>
</listitem>
<listitem>
<para>
<firstterm>プレライト(Prelight)</firstterm>: 例として, マウスが
ウィジェット上にあり (そして特に, クリックが影響を及ぼしている),
ボタン上を移動すると, ボタンは"ハイライト"になります。
</para>
</listitem>
<listitem>
<para>
<firstterm>選択(Selected)</firstterm>: ウィジェットがリスト
もしくは, その他の方法の組合せに存在し, 現行では任意で選択
されます。
</para>
</listitem>
<listitem>
<para>
<firstterm>非応答(Insensitive)</firstterm>: ウィジェットは,
"ゴースト化", または非活発, もしくは非反応になります。
入力に対して反応しません。
</para>
</listitem>
</itemizedlist>
<para>
与えられた動作状態の正確な意味や可視的表示は, 特にウィジェットと
カレントテーマに依存します。ウィジェットの動作状態には,
<function role="macro">GTK_WIDGET_STATE()</function>
(<xref role="mlref" linkend="ml-widgetstate">)でアクセスできます。
このマクロは, 定数
<structname role="C">GTK_STATE_NORMAL</structname>, <structname
role="C">GTK_STATE_ACTIVE</structname>, <structname
role="C">GTK_STATE_PRELIGHT</structname>, <structname
role="C">GTK_STATE_SELECTED</structname>, または <structname
role="C">GTK_STATE_INSENSITIVE</structname>の 1つを返します。
</para>
<figure role="macrolist" id="ml-widgetstate">
<title id="ml-widgetstate.title">動作状態アクセス構造</title><funcsynopsis
role="macrolist" id="ml-widgetstate.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkwidget.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef> <function
role="macro">GTK_WIDGET_STATE</function></funcdef>
<paramdef><parameter>widget</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect3>
</sect2>
</sect1>
<sect1 id="sec-mainloop">
<title>メインループ</title>
<para>
GTK+メインループの主な役割は, Xサーバに接続しているファイルの記述子上に
あるイベントに注目し, それらをウィジェットに転送します。<xref
linkend="sec-gtkevents"> は, メインループのイベント処理を更に詳しく
解説しています。この章では, 一般的な面でのメインループについて説明し,
そして新しい機能をメインループに追加する方法を解説します。つまり,
ループが特定の間隔でアイドル(idle)しているとき, ファイル記述子が
読み込みもしくは書き込みの準備ができているとき, そしてメインループが
存在するとき起動されるコールバックについてです。
</para>
<sect2 id="sec-gtk-mainloop">
<title>メインループの基本</title>
<para>
メインループは, 主として glibに実装されています。glibには, 一般的な
メインループの抽象が存在します。GTK+は, glibメインループをGDK Xサーバ
接続に付け加え, 便利なインタフェースを作成します。( glibのループは,
GTK+のループよりわずかながら低レベルです。) GTK+メインループ
インタフェースの核は, <xref role="flref" linkend="fl-mainloop">に
示されています。
</para>
<para>
<function>gtk_main()</function> がメインループを起動します。
<function>gtk_main()</function> は,
<function>gtk_main_quit()</function> がコールされるまで戻りません。
<function>gtk_main()</function> が, 再帰的にコールされることもでき
ます。各<function>gtk_main_quit()</function> へのコールが,
<function>gtk_main()</function>の 1インスタンスを終了します。
<function>gtk_main_level()</function>は, 再帰レベルを返します。つまり,
<function>gtk_main()</function>がスタック上にない場合は 0を返し,
<function>gtk_main()</function>が1つ稼働している場合は, 1を返します。
</para>
<para>
<function>gtk_main()</function>の全インスタンスは, 機能的には同一です。
Xサーバへの同接続をみて, 同イベントキューから作業を行います。
<function>gtk_main()</function>インスタンスは, ブロックに用いられます。
ある条件が重なるまで関数の流動制御は停止しています。全てのGTK+
プログラムが, アプリケーション起動中<function>main()</function>を
終了から遠ざけるためにこの手法を用います。
<function>gnome_dialog_run()</function> 関数 ( <xref
linkend="sec-modaldialogs">をご覧下さい。) は, 再帰的メインループを
用います。そのためユーザがダイアログボタンをクリックするまで
復帰しません。
</para>
<para>
時には, いくつかのイベント処理を<function>gtk_main()</function>への
制御といった流れを介さずに行いたい場合があるでしょう。
<function>gtk_main_iteration()</function>をコールすることで,
メインループの単一的な繰り返しが可能です。このようにすると,
例えばシングルイベントを処理できるでしょう。つまり, 何のタスクが未処理
かに依存します。全てのイベントが
<function>gtk_events_pending()</function>の属性をコールして処理する
必要性があるかどうかの確認もできます。これら2つの関数を一括すると,
GTK+に一時的制御を復帰することができます。そのため GUIが, "追いつく"
ことができるのです。例えば, 計算処理が長い場合プロセスバーを表示
したいかもしれません。そのような場合は, GTK+メインループに時間的な
起動を可能にしなければなりません。そうすれば, GTK+は再度プロセスバーを
再描画できます。次のコードを用いて下さい。
</para>
<programlisting>
while (gtk_events_pending())
gtk_main_iteration();
</programlisting>
<figure role="functionlist" id="fl-mainloop">
<title id="fl-mainloop.title">メインループ</title><funcsynopsis
role="functionlist" id="fl-mainloop.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkmain.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>void <function>gtk_main</function></funcdef>
<void>
</funcprototype>
<funcprototype>
<funcdef>void <function>gtk_main_quit</function></funcdef>
<void>
</funcprototype>
<funcprototype>
<funcdef>void <function>gtk_main_iteration</function></funcdef>
<void>
</funcprototype>
<funcprototype>
<funcdef>gint <function>gtk_events_pending</function></funcdef>
<void>
</funcprototype>
<funcprototype>
<funcdef>guint <function>gtk_main_level</function></funcdef>
<void>
</funcprototype>
</funcsynopsis>
</figure>
</sect2>
<sect2 id="sec-gtk-quit">
<title>終了関数</title>
<para>
<firstterm>終了関数(quit function)</firstterm> は,
<function>gtk_main_quit()</function>がコールされると起動されるコール
バックです。言い換えると, コールバックは,
<function>gtk_main()</function>が復帰する直前に起動します。
コールバックは, <structname role="C">GtkFunction</structname>で
なければならず, 次のように定義します。
</para>
<programlisting>
typedef gint (*GtkFunction) (gpointer data);
</programlisting>
<para>
終了関数は, <function>gtk_quit_add()</function>
(<xref role="flref" linkend="fl-quitfuncs">) で追加されます。
終了関数が追加されると, メインループレベルを
<function>gtk_main_level()</function> で返すといったように指定
しなければなりません。 第2,そして第3引数は,コールバック及び
コールバックデータを指定します。
</para>
<para>
コールバックの戻り値は, コールバックが再度行われるべきかどうかを
指示します。コールバックが, <structname role="C">TRUE</structname>
を返すと, 反復的に起動されます。<structname role="C">FALSE</structname>
が返されるとすぐに, 接続が中断されます。全終了関数が
<structname role="C">FALSE</structname>を返すと
<function>gtk_main()</function>が復帰します。
</para>
<para>
<function>gtk_quit_add()</function> は, ID を返します。そのIDは,
<function>gtk_quit_remove()</function>を使って終了関数を削除する際
使用されます。コールバックデータを
<function>gtk_quit_remove_by_data()</function>に渡すことでも, 終了関数
を取り除くことができます。
</para>
<figure role="functionlist" id="fl-quitfuncs">
<title id="fl-quitfuncs.title">終了関数</title><funcsynopsis
role="functionlist" id="fl-quitfuncs.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkmain.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>guint <function>gtk_quit_add</function></funcdef>
<paramdef>guint
<parameter>main_level</parameter></paramdef><paramdef>GtkFunction
<parameter>function</parameter></paramdef><paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_quit_remove</function></funcdef>
<paramdef>guint
<parameter>quit_handler_id</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_quit_remove_by_data</function></funcdef>
<paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
<sect2 id="sec-gtk-timeout">
<title>タイムアウト関数</title>
<para>
<firstterm>タイムアウト関数(Timeout functions)</firstterm> は,
終了関数のように確実に接続そして切断されます。予想されるコールバック
は, 同様です。<function>gtk_timeout_add()</function> は, <structname
role="C">interval</structname> 引数を期待しています。コールバックは,
<structname role="C">interval</structname>ミリセカンド毎に
起動されます。コールバックが, <structname role="C">FALSE</structname>
を返すと, タイムアウト関数のリストから取り除かれます。ちょうど,
<function>gtk_timeout_remove()</function>をコールしたような状況です。
タイムアウト関数内から<function>gtk_timeout_remove()</function>を
コールするのは安全ではありません。GTK+がループを行っている間は,
タイムアウトリストが変更されているため, クラッシュを引き起こして
しまいます。かわりに, 関数を取り除く際に, <structname
role="C">FALSE</structname> を返して下さい。
</para>
<figure role="functionlist" id="fl-timeoutfuncs">
<title id="fl-timeoutfuncs.title">タイムアウト関数</title><funcsynopsis
role="functionlist" id="fl-timeoutfuncs.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkmain.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>guint <function>gtk_timeout_add</function></funcdef>
<paramdef>guint32
<parameter>interval</parameter></paramdef><paramdef>GtkFunction
<parameter>function</parameter></paramdef><paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_timeout_remove</function></funcdef>
<paramdef>guint
<parameter>timeout_handler_id</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
<sect2 id="sec-gtk-idle">
<title>アイドル関数</title>
<para>
<firstterm>アイドル関数(Idle functions)</firstterm> は,
GTK+のメインループがその他なにも行わない間, 継続的に起動します。
アイドル関数は, イベントキューが空の時のみ起動します。
メインループは通常アイドル状態になり, 何かが起こるのを待機しています。
<structname role="C">TRUE</structname>が返されると, 繰り返し起動
されます。<structname role="C">FALSE</structname>が返されると,
取り除かれます。ちょうど, <function>gtk_idle_remove()</function>が
コールされたような状況です。
</para>
<para>
アイドル関数 APIは, <xref role="flref"
linkend="fl-idlefuncs">に示されてますが, タイムアウト関数, 終了関数の
APIと同一です。前記のように, <function>gtk_idle_remove()</function>
は, アイドル関数内からコールすべきではありません。というのは, GTK+
アイドル関数リストを腐敗してしまうからです。
アイドル関数を取り除く際は, <structname role="C">FALSE</structname>を
返して下さい。
</para>
<para>
アイドル関数は, 大体において"ワンショット"コードをキューにするのに
役立ちます。つまり, 全イベントが処理された後起動されます。GTK+のサイズ
調整や<classname role="widget">GnomeCanvas</classname> の再描写のよう
な比較的高級な操作は, アイドル関数で行われ,
<structname role="C">FALSE</structname>を返しています。これは,
高級な操作は, たとえ多様連続イベントが独立的に再計算を要求する
としても, 一度しか実行されないとの裏付けになります。
</para>
<para>
GTK+メインループは, 単純な予想を含んでいます。アイドル関数は, 実際
UNIXの行程が行うように, 優先順位を割り当てます。アイドル関数に,
デフォルトではない優先順位を割り当てることもできますが,
それは複雑な話になるので本書の範囲外です。
</para>
<figure role="functionlist" id="fl-idlefuncs">
<title id="fl-idlefuncs.title">アイドル関数</title><funcsynopsis
role="functionlist" id="fl-idlefuncs.synopsis">
<funcsynopsisinfo>
#include <gtk/gtkmain.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>guint <function>gtk_idle_add</function></funcdef>
<paramdef>GtkFunction
<parameter>function</parameter></paramdef><paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_idle_remove</function></funcdef>
<paramdef>guint
<parameter>idle_handler_id</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gtk_idle_remove_by_data</function></funcdef>
<paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
<sect2 id="sec-gtk-input">
<title>入力関数</title>
<para>
<firstterm>入力関数(Input functions)</firstterm> GDKレベルで処理
されます。与えられたファイル記述子が読み込みまたは, 書き込みの準備が
できると起動されます。特に, ネットワークアプリケーションに役立ちます。
</para>
<para>
入力関数を追加するには, モニタへのファイル記述子, 期待する(読み込み
書き込みの準備ができている)動作状態, そしてコールバック/データの組合せ
を指定します。<xref role="flref" linkend="fl-inputfuncs"> は, APIを
示しています。関数は, <function>gdk_input_add()</function>による
戻り値を使って取り除くことができます。終了関数, タイムアウト関数,
そしてアイドル関数と異なり, 入力関数内から
<function>gdk_input_remove()</function>をコールしても安全です。
GTK+は, 入力関数のリストを経てループする中間点ではありません。
</para>
<para>
期待する条件を指定するには, <structname
role="C">GdkInputCondition</structname> フラグを用いて下さい。
<structname role="C">GDK_INPUT_READ</structname>, <structname
role="C">GDK_INPUT_WRITE</structname>, そして <structname
role="C">GDK_INPUT_EXCEPTION</structname>のことです。
ORで, 1つ以上のフラグを一括することもできます。
これらは<function>select()</function>システムに渡される3つの
ファイル記述子に対応してコールします。詳細については, 優れたUNIXの本
にゆだねます。条件がかみ合うとなると, 入力関数は起動します。
</para>
<para>
コールバックは次のようにすべきでしょう。
</para>
<programlisting>
typedef void (*GdkInputFunction) (gpointer data,
gint source_fd,
GdkInputCondition condition);
</programlisting>
<para>
これで, コールバックデータ, 見られているファイル記述子, かみ合った条件
を受け取ります。(恐らく気になっていたことのサブセットでしょう。)
</para>
<figure role="functionlist" id="fl-inputfuncs">
<title id="fl-inputfuncs.title">入力関数</title><funcsynopsis
role="functionlist" id="fl-inputfuncs.synopsis">
<funcsynopsisinfo>
#include <gdk/gdk.h>
</funcsynopsisinfo>
<funcprototype>
<funcdef>gint <function>gdk_input_add</function></funcdef>
<paramdef>gint
<parameter>source_fd</parameter></paramdef><paramdef>GdkInputCondition
<parameter>condition</parameter></paramdef><paramdef>GdkInputFunction
<parameter>function</parameter></paramdef><paramdef>gpointer
<parameter>data</parameter></paramdef></funcprototype>
<funcprototype>
<funcdef>void <function>gdk_input_remove</function></funcdef>
<paramdef>gint <parameter>tag</parameter></paramdef></funcprototype>
</funcsynopsis>
</figure>
</sect2>
<para>日本語翻訳:レーザーファイブ (info@xxxxxxxxxxxx)</para>
</sect1>
</chapter>