この章では、Sun WorkShop Visual の構造化コード生成機能を使用して、再使用可能なウィジェット階層を作成する方法を説明します。この機 能は、再使用可能なウィジェット階層を作成する上で、非常に便利です。これらの再使用可能階層は定義と 呼ばれ、ウィジェットパレット上に存在します。また、他のウィジェットと同様、階層に追加することもで きます。定義の詳細についても、本章で記述します。
Sun WorkShop Visual は、ユーザーの生成コードを構造化し、柔軟性を高め、簡単に再使用ができるようにする制御機能を備えて います。この項を読む前に、「基本モジュールの分析」 で説明されているデフォルト生成コードの構造を再度読み返し、理解しておくことをお勧めします。特にデ フォルトのコードでは、デザイン中の各シェルごとに別々の作成関数があることに注意してください。ウィ ジェットに名前が付けられていない場合、そのウィジェットは局所的に宣言されます。また、名前が付けら れている、あるいはウィジェットがアプリケーションシェルである場合は大域的に宣言されます。
コードを構造化するための Sun WorkShop Visual の制御機能は、コアリソースパネルの「コード生成」のページにあります。
構造化コード生成の最も簡単な例は、ウィジェットを関数構造体として指定するも のです。これにより、Sun WorkShop Visual はウィジェットとその子孫を作成する独立した関数を生成します。この関数は、格納ウィジェットの作成関 数によって呼び出されます。
ウィジェットを関数構造体として指定するには、コアリソースパネルの「コード生 成」ページを選択し、「構造」オプションメニューから「関数」を選択します。
図 8-1 に示されている階層は、わかりやすくするために多少単純化されていますが、次のコードを生成します。 1
Widget shell = (widget) NULL;
Widget form = (Widget) NULL;
Widget button_box = (Widget) NULL;
Widget b1 = (Widget) NULL;
Widget create_button_box (Widget parent)
{
Widget children[1]; /* マネージする子 */
Arg al [64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
Widget button_box = (Widget) NULL;
button_box = XmCreateRowColumn ( parent,
"button_box", al, ac );
b1 = XmCreatePushButton ( button_box, "b1", al, ac);
children[ac++] = b1;
XtManageChildren(children, ac);
/* ボタンボックスが作成され、マネージされずに返されます */
return button_box;
}
/* シェルの作成関数がボタンボックス作成関数を呼び出します */
void create_shell (Widget parent)
{
Widget children[1]; /* マネージする子 */
Arg al[64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
XtSetArg (al[ac], XmNallowShellResize, TRUE); ac++;
shell = XmCreateDialogShell ( parent, "shell", al, ac );
ac = 0;
XtSetArg (al[ac], XmNautoUnmanage, FALSE); ac++;
form = XmCreateForm ( shell, "form", al, ac );
ac = 0;
button_box = create_button_box ( form );
/* ボタンボックスのコンストレイント・リソースが親の作成関数内に設定されます */
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
XtSetValues ( button_box,al, ac );
children[ac++] = button_box;
XtManageChildren(children, ac);
}
ここで、モジュールは、階層全体を作成するための create_Shell() 、およびボタンボックスを作成するための create_button_box() という 2 個の関数を持っていることになります。
次のタイプのコード構造は、データ構造体です。これは、Sun WorkShop Visual がウィジェットとその子孫に対して独立した作成関数を生成する点で、関数構造体に似ています。ウィジェ ットがデータ構造体として指定された場合、Sun WorkShop Visual はウィジェットおよびその子孫を含む構造体に対して typedef を生成します。ウィジェットの作成によって、その型の構造体が作成、設定され、その構造体へのポインタ が返されます。削除関数 ( delete_ <ウィジェット名>) も生成されるため、割り当てられたメモリーを解放することができます。
ウィジェットをデータ構造体として指定するには、コアリソースパネルから「コー ド生成」ページを選択し、「構造」オプションメニューから「データ構造体」を選択します。
前に示した階層使用 (ただし、 button_box をデータ構造体として指定) すると、以下のコードが生成されます。
/* 最初に、データ構造体に対しての型宣言が生成されます */ 2
typedef struct button_box_s {
Widget button_box;
Widget b1;
} button_box_t, *button_box_p;
Widget shell = (Widget) NULL;
Widget form = (Widget) NULL;
button_box_p button_box = (button_box_p) NULL;
/* 作成関数によって button_box 構造体へのポインタが返されます */
button_box_p create_button_box (Widget parent)
{
Widget children[1]; /* マネージする子 */
button_box_p button_box = (button_box_p)NULL;
/* 構造体にスペースが割り当てられ、フィールドが埋められます */
button_box = (button_box_p) XtMalloc ( sizeof (
button_box_t ) );
button_box->button_box = XmCreateRowColumn ( parent,
"button_box", al, ac );
button_box->b1 = XmCreatePushButton
( button_box->button_box, "b1", al, ac );
children[ac++] = button_box->b1;
XtManageChildren(children, ac);
return button_box;
}
/* 割り当てられたメモリーを解放するための削除関数が提供されます */
void delete_button_box (button_box_p button_box)
{
if ( ! button_box )
return;
XtFree ( ( char * )button_box );
}
/* 再度シェル作成関数がボタンボックス作成関数を呼び出します */
void create_shell (Widget parent)
{
Widget children[1]; /* マネージする子 */
Arg al[64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
shell = XmCreateDialogShell ( parent, "shell", al, ac );
form = XmCreateForm ( shell, "form", al, ac );
button_box = create_button_box ( form );
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM);
ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM);
ac++;
/* button_box ウィジェットは、構造体内部で参照されます */
XtSetValues ( button_box->button_box,al, ac );
ac = 0;
children[ac++] = button_box->button_box;
XtManageChildren(children, ac);
ac = 0;
}
C++ クラスの使用方法は、データ構造体の場合と非常によく似ています。
Sun WorkShop Visual は階層内の個々のウィジェットを
C++
のクラスを使用して隠ぺいすることはしませんが、そのかわり階層の一部分を独自のクラスとして指定しま
す。C++
のクラスとして指定されたウィジェットには対応したクラスが定義されます。そのウィジェットの名前の付
いた子孫ウィジェットは、クラスのメンバーとなり、ウィジェット作成およびウィジェット破壊のメソッド
が供給されます。また、クラスにそれ自体がクラス (のポインタ)
であるメンバーが含まれる場合には、これらのメンバーを作成および破壊するためのコンストラクタ、およ
びデストラクタ・メソッドが生成されます。ウィジェットはクラスのインスタンス作成時に作成されるので
はなく、ウィジェット作成関数が明示的に呼び出された場合に作成されることに注意してください。したが
って、クラスのインスタンスを破壊することによって、ウィジェットが破壊されることはありません。
ウィジェットを C++ クラスとして指定するには、コアリソースパネルの「コード生成」ページを選択し、「構造」オプションメ ニューから「C++/Java クラス」を選択します。ウィジェットを C++ クラスとして指定し、C を生成する場合には、ウィジェットはデータ構造体として扱われるので、注意してください。
この節では C++ クラスについて説明します。Sun WorkShop Visual の Java クラスについての詳細は、第 10 章「Java 用のデザイン」を参照してください。
この例で生成されるコードを以下に示します。わかりやすくするために、簡略化し てあります。3
button_box および shell に対してクラスが宣言されます。
class button_box_c: public xd_XmRowColumn_c {
public:
virtual void create (Widget parent, char *widget_name =
NULL);
protected:
Widget button_box;
Widget b1;
Widget b2;
};
typedef button_box_c *button_box_p;
shell クラスはコンストラクタとデスクトラクタ関数を持ちます。これは、クラス (またはデータ構造体) ヘのポインタであるメンバーを持っているためです。
class shell_c: public xd_XmDialog_c {
public:
virtual void create (Widget parent, char *widget_name = NULL);
shell_c();
virtual ~shell_c();
protected:
Widget shell;
Widget form;
Widget text;
button_box_p button_box;
};
typedef shell_c *shell_p;
shell_p shell = (shell_p) NULL;
この時点で、作成関数はクラスのメソッドとなります。このメソッドは、本リリー スで提供される Sun WorkShop Visual の基底クラスにおいて公開宣言されます。
void button_box_c::create (Widget parent, char *widget_name)
{
Widget children[2]; /* マネージする子 */
Arg al[64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
if ( !widget_name )
widget_name = "button_box";
button_box = XmCreateRowColumn ( parent, widget_name,
al, ac );
_xd_rootwidget は部分階層のルートにあるウィジェットを保存するクラスの限定公開メンバーです。これにより、基底クラ スはウィジェットを操作することができます。
_xd_rootwidget = button_box;
b1 = XmCreatePushButton ( button_box, "b1", al, ac );
b2 = XmCreatePushButton ( button_box, "b2", al, ac );
children[ac++] = b1;
children[ac++] = b2;
XtManageChildren(children, ac);
ac = 0;
}
シェルの作成メソッドは、ボタンボックスの作成メソッドを呼び出します。
void shell_c::create (Widget parent, char *widget_name)
{
Widget children[2]; /* マネージする子 */
Arg al[64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
if ( !widget_name )
widget_name = "shell";
XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
shell = XmCreateDialogShell ( parent, widget_name, al,
ac );
ac = 0;
_xd_rootwidget = shell;
XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
form = XmCreateForm ( shell, "form", al, ac );
ac = 0;
text = XmCreateText ( form, "text", al, ac );
ボタンボックスクラスは、コンストラクタ・メソッドでインスタンス生成されるた め、この時点ではウィジェットのみが作成される必要があります。
button_box->create ( form, "button_box" );
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM);
ac++;
XtSetArg(al[ac], XmNtopWidget,
button_box->xd_rootwidget( )); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM);
ac++;
XtSetValues ( text,al, ac );
ac = 0;
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET);
ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM);
ac++;
XtSetValues ( button_box->xd_rootwidget(),al, ac );
ac = 0;
children[ac++] = text;
children[ac++] = button_box->xd_rootwidget();
XtManageChildren(children, ac);
ac = 0;
}
shell_c::shell_c()
{
button_box = new button_box_c;
}
shell_c::~shell_c()
{
delete button_box;
}
ウィジェットが C++ クラスに指定され、C コードが生成される場合、ウィジェットはデータ構造体と同様に扱われます。
デフォルトでは、生成クラスは Sun WorkShop Visual の基底クラスの 1 つから派生しますが、「C++ アクセス」オプションメニューの下のフィールドに基底クラスを指定して、変更することもできます。本リ リースで供給される Sun WorkShop Visual 基底クラスは、生成コードを正確に実行するための最小限のサポートを提供しています。これらのクラスを 変更および拡張すると、ご使用の GUI 開発手法に適した再使用可能なメソッドを作成することができます。
子孫ウィジェットは名前が付けられている場合、あるいはそれ自体がデータ構造で あったり C++ クラスである場合は、クラスの限定公開メンバーとして現れます。したがって、C++ クラスウィジェットそのもの、およびクラスメンバーとして呼び出す必要のある子孫に名前を付けることは 重要です。デフォルトのアクセス制御の変更は、「C++ アクセス」オプションメニューから必要なレベル (公開、限定公開、または非公開) を選択することにより実行できます。
C++ クラスウィジェットに対して、名前の付けられていないウィジェットを使用した場合でも、即座にエラーが 生じることはありません。しかし、Sun WorkShop Visual が名前の付けられていないウィジェットに対して自動的に割り当てる数は、階層の編集時に変更される可能 性があるため、名前の付けられていないウィジェットを使用することはお勧めできません。
コールバック関数を呼び出す X ツールキット関数は、以下の形式のコールバック関数をとります。
void my_callback (Widget, XtPointer, XtPointer)
通常のメンバー関数はコールバック関数には適していません。これは C++ コンパイラが、オブジェクトに対してインスタンスデータを検索する最初の引数 ( this ポインタ) を X メンバー関数に余分に渡してしまうためです。コールバック関数として通常のメンバー関数を使用すると、 メンバー関数はウィジェットポインタをインスタンスデータポインタとして解釈するため、意図したとおり には動作しません。
Sun WorkShop Visual は、この問題を回避するために一般によく使用される技術を使用しています。静的メンバー関数 ( this ポインタを予定していない) が宣言され、コールバック関数として使用されます。
static void my_callback (Widget, Xtpointer call_data, XtPointer client_data)
インスタンスへポインタを引き渡すためには、クライアントデータ (client_data) 引数が使用されます。静的メンバー関数は、単にインスタンスポインタを使用して通常の非静的メンバー関 数を呼び出し、そのウィジェットと引数 (call_data) を渡します。非静的メンバー関数は、以下の形式をとります。
virtual void my_callback (Widget, XtPointer call_data)
Sun WorkShop Visual は、両方の関数宣言、静的コールバック関数に対する全コード、およびユーザーの書いた標準メンバー関数 に対するスタブを生成します。この関数は仮想として宣言されているため、動作を変更するために派生クラ スにおいて書き換えることができます。この手法については、ダグラス A ヤング著、磯谷正孝訳の『オブジェクト指向プログラミングと C++: OSF/Motif 版』 (Douglas Young 『 Object-Oriented Programming with C++ and OSF/Motif 』) に詳しく記述されています。
コールバック・メソッドを追加する場合は、まだそのメソッドが宣言されていなけ ればその宣言も追加されます。「コールバック」ダイアログ内の「メソッド」ボタンを押すと、現在選択し ているウィジェットを包含するクラスで宣言されているメソッドが表示されます。
Sun WorkShop Visual はデフォルトで、メソッドを純粋仮想ではなく、公開アクセスを持つものとして宣言します。これらの属性 を変更したい場合は、「メソッド宣言」ダイアログを使用して変更してください。詳細は、「メソッド宣言」を参照してください。
コールバックをメソッドとして追加する場合は、効率的に処理するために、Sun WorkShop Visual はメソッドの宣言をそのウィジェットの包含するクラスに追加します。包含するクラスであるウィジェット を選択し、「ウィジェット」メニューから「メソッド宣言」を選択することにより、メソッド宣言の表示、 追加および削除を行うことができます。メソッド宣言ダイアログを図 8-3 に示します。
「構造の色」で説明するように「表示」メニューの「構造の色」を使用し、メソッドを追加し たウィジェットに最も近い上位クラスを選択します。このウィジェットが C++ クラスとして定義されている場合は、これは当然同じウィジェットとなります。
デフォルトでは、Sun WorkShop Visual の追加するメソッドのアクセスは「公開」です。「メソッド宣言」ダイアログにある「アクセス」オプショ ンメニューを使用すると、個々のコールバック・メソッドに対してのアクセスを、「公開」、「非公開」、 「限定公開」の中からを選択できます。
「純粋仮想」トグルを設定して、非静的メンバー関数を純粋仮想関数として宣言す ることができます。たとえば、このトグルをメニューバークラスのコールバック・メソッド OnNew() に設定した場合、Sun WorkShop Visual はメソッドを以下のように宣言します。
class menubar_c: public xd_XmMenubar_c {
...
public:
...
virtual void OnNew( Widget, Xtpointer) = 0;
};
この関数は純粋仮想関数であるため、
menubar_c
は抽象クラスとなり、
menubar_c::OnNew()
の実装を行う必要はありません。
menubar_c
のインスタンスを作成することはできませんが、他のクラスの基底クラスとして使用することが可能となり
ます。
コールバック・メソッドをウィジェットから削除するということは、単にそのメソ ッド (ウィジェットへのコール) の使用を止めるということを意味します。Sun WorkShop Visual でコールバック・メソッドを追加すると、メソッドの宣言が自動的に追加されます。メソッドの宣言も一緒 に削除したい場合は、包含するクラスであるウィジェットのメソッド宣言リストから宣言を削除する必要が あります。詳細な手順および Sun WorkShop Visual を使用して追加された宣言の詳細は、 「メソッド宣言」を参照してください。
上記のように、追加されたコールバック・メソッドは包含するクラスで宣言されま す。このウィジェット (包含するクラス) の構造体を変更した結果ウィジェットがクラスでなくなると、メソッドは無効になります。このような場合 、Sun WorkShop Visual は図 8-4 に示すような 「無効化されたメソッド」 ダイアログを表示します。
このダイアログはモード付きなので、デザインで作業を続けるにはダイアログを閉 じなければなりません。このダイアログが表示されるのは、メソッド宣言が無効になるようにウィジェット の構造体を変更したときだけです。
左側のウィジェットリストには、構造体を変更することでメソッドが無効化される すべてのウィジェットが表示されます。ウィジェットを選択すると、無効化されたメソッドが右側に表示さ れます。選択した各メソッドについて、現在宣言されているクラスと、メソッドを宣言できる新しいクラス がこのダイアログに表示されます。「提示されたクラス」 は常に最上位に最も近い上位クラスです。適当なクラスが他に存在しない場合は、このダイアログはメソッ ドが関数になることを警告します。
「宣言」 を押すと、選択したメソッドの宣言が 「提示されたクラス」 に変わります。「すべてを宣言」 を押すと、無効化された各メソッドがそれぞれの 「提示されたクラス」 に変わります。
「コードプレリュード」ダイアログを使用して、C++ クラスにデータや関数メンバーを追加することができます。「公開メソッド」、「限定公開メソッド」また は「非公開メソッド」を選択し、テキスト領域 (直接編集している場合はコード) に宣言を入力します。基本モジュールおよび外部宣言ファイルの両方のクラス宣言に C++ コードプレリュードが生成されます。
クラスに関数を追加する場合、Sun WorkShop Visual によって生成されたクラスから派生した新しいクラスを書くことをお勧めします。派生クラスと生成された 基底クラス間の論理的な違いを使用して、メンバーを追加して仮想関数を実装することができます。
デフォルトでは、Sun WorkShop Visual はルートウィジェットの変数名をもとに C++ クラス名を決定します。したがって、ウィジェット menubar のクラスは menubar_c となります。
class menubar_c: public xd_XmMenuBar_c {
...
};
Sun WorkShop Visual はクラスのインスタンスを作成するコードを生成する場合に、同じ名前を使用します。
menubar = new menubar_c;
Sun WorkShop Visual がクラスをある名前で生成し、別の名前でインスタンスを作成するようにデフォルト動作を変更することが できます。
menubar = new mymenubar_c;
デフォルトでは、Sun WorkShop Visual はルートウィジェットの型に適した基底クラスから生成クラスを派生させます。たとえば、ウィジェット階 層のルートにメニューバーを持つクラスは、 xd_XmMenuBar_c から派生しています。基底クラスの名前は、コアリソースパネルで変更することができます。
Sun WorkShop Visual 製品には、基底クラスの実装例が含まれています。これらをそのまま、あるいは修正を加えて使用して、特 定のアプリケーションの分野に適した機能を追加することができます。
実装例の基底クラスを構築するためのメークファイルも含まれています。Sun WorkShop Visual は基底クラスについて以下の 2 点を仮定します。
これらの仮定は、クラス xd_base_c 中で使用されています。このクラスには他のいくつかの基本的な制約も存在します。
class xd_base_c
{
public:
xd_base_c() {_xd_rootwidget=NULL;}
Widget xd_rootwidget() const {return _xd_rootwidget;}
protected:
Widget _xd_rootwidget;
private:
void operator=(xd_base_c&); // 代入なし
xd_base_c(xd_base_c&); // デフォルトのコピーなし
};
Sun WorkShop Visual は、使用される基底クラスについてその他の制約は行いません。つまり言い換えると、基底クラスのセット は、それらが xd-base_c (または別の基底クラスで Sun WorkShop Visual の仮定を満たすもの) から派生したものであれば使用可能です。
基底クラスのコンストラクタに対して、クラス名と一緒に実際の引数を渡すことも 可能です。引数が供給される場合 (基底クラス文字列が '()' を含んでいる場合)、そのクラスはコンストラクタを持つように強制され、引数文字列は基底クラスに渡さ れます。たとえば、ウィジェット menubar に対して「基底クラス」文字列を mymenubar_c ("Hello World") に設定すると、Sun WorkShop Visual は以下のように生成を行います。
class menubar_c : public mymenubar_c {
public:
menubar_c();
...
};
...
menubar_c::menubar_c () : mymenubar ( "Hello World" )
{
}
...
menubar = new menubar_c;
子のみ生成構造体オプションを選択すると、あるウィジェット (子のみを生成するウィジェット) を別の構造体を保持するための構造体として指定することができます。 子のみを生成するウィジェットは、階層内のそれらの子孫に対してのコンテキストを提供しますが、子のみ を生成するウィジェット自身に対してのコードは生成しません。以下に示す例を考察してみましょう。
図 8-5 に示すデザインからコードを生成する場合、Sun WorkShop Visual はメニュー構造に対してのみコードを作成します。この機能を使用すると、アプリケーションプログラムで 制御可能なデザインの一部分だけを生成することができます。
何らかの構造を含むデザインに対して UIL を生成する場合の手順は、基本的には C および C++ の場合と同じです。独立した階層が UIL ファイルに生成され、それぞれの作成関数がコードファイルに生成されます。作成関数は UIL 階層から適切なウィジェットを取り出し、適切にデータ構造フィールドへの記入を行います。
ウィジェットは通常、何らかの方法で構造化されていない場合、あるいは名前が付 けられていない場合には、閉じた作成関数内で局所的に宣言されます。ウィジェットが構造化されているか 、名前が付けられている場合には、それらはそれが含まれる構造体 (存在する場合) 内で、あるいは大域的変数として宣言されます。このデフォルト動作は、コアリソースパネルにあるウィジ ェットの記憶クラスを設定することにより、変更できます。記憶クラスを「局所」に設定すると、本来は大 域的として宣言される、または構造体内で宣言されるはずのウィジェットが作成関数に対して局所的に宣言 されます。記憶クラスを「大域」に設定すると、名前の付いていないウィジェットまたは構造の中の名前の 付いた要素が大域的に宣言されます。「大域」設定は、ウィジェット型リソースおよび 「到達不能ウィジェット」で説明されているリンクに対して特に有効です。「静的」オプショ ンは「大域」に似ていますが、宣言はモジュールに対して静的です。
名前の付いていないウィジェットを強制的にデータ構造にすることはできません。 名前のないデータ構造ウィジェットの子は、データ構造の作成関数に対して局所的に作成され、管理されま す。
ブリテンボード用の XmNdefaultButton のようなウィジェット型のリソースと一緒に、あるいはリンクと一緒に構造化コード生成を使用する場合、 範囲外のウィジェットを参照するデザインを指定してしまうことがあります。これらは、到達不能ウィジェ ットとみなされます。Sun WorkShop Visual は、このような事例の検出を行い、コード生成時に警告を発します。また、「子のみ生成」構造体を使用し た場合や階層を実行時に動的に作成した場合、到達不能ウィジェットが予想外の障害を発生させる可能性も あります。
図 8-6 に到達不能ウィジェットを示します。 b1 はフォームの作成関数からアクセス可能でデフォルトボタン引数として使用可能でなければなりません。し かし、 b1 は button_box 関数に対して局所的であるため、フォームの作成関数のスコープには入っていません。Sun WorkShop Visual は、この状況を検出すると、以下の警告をコード生成時に表示します。
コードは生成されますが、予想通りにはコンパイル、あるいは実行しない場合があ ります。この場合の最も簡単な解決方法は、記憶クラスオプションを使用して適切なウィジェットを強制的 に大域的と指定することです。
ウィジェットの階層が構造 (C++ クラスまたは C 構造体) としてカプセル化された場合、それを定義に変化させることにより、他のデザインで再使用することができ ます。定義とは Sun WorkShop Visual のウィジェットパレットに追加して、再使用できるウィジェット階層です。パレットから定義を選択するこ とにより、デザインに定義のインスタンスが作成されます。このインスタンスをさらに修飾し、再び定義に することも可能です。
定義を指定する場合、対象となるウィジェットを含むデザインファイルが保存され 、かつ、対象となるウィジェットに定義として印が付けられている必要があります。ウィジェットに定義と しての印をつけるためには、「ウィジェット」メニューにある「定義」を使用します。定義を作成すると、 その中のウィジェットは凍結され、ウィジェットのリソースパネルは使用不可能となるため、ウィジェット の追加やウィジェット名の変更を行うことはできません。一時的に定義の指定を解除して、定義を構成する ウィジェットを編集することはできます。ただし、定義を使用するデザインとの矛盾を避けるため、この操 作は慎重に行なってください。詳細は、「定義の変更」を参照してください。
他のデザインにおいて定義を使用可能にするためには、Sun WorkShop Visual はその定義に対しての外部参照を必要とします。これは、「定義を編集」ダイアログで編集できる「定義」 ファイルにより提供されます。
Sun WorkShop Visual は、定義ファイルを読み出して、その内容をパレットに表示します。定義ファイル名は、 definisionFileName リソースの設定により指定されます。デフォルト値は $HOME/.xddefinitionsrc です。
複数のプロジェクトで作業を進める必要があり、それぞれのプロジェクトが異なる 定義のセットを使用する場合、リソースを設定して定義ファイルを変更することができます。以下に例を示 します。
visu.definitionsFileName:/home/project6/xddefs
このリソースの値は環境変数を含むことができます。以下に例を示します。
visu.definitionsFileName:$PROJECT_ROOT/xddefs
新しい設定に変更する場合は、Sun WorkShop Visual を終了して再起動します。
定義ファイルの変更は、「パレット」メニューにある「定義を編集」ボタンを使用 して行います。このボタンは、図 8-8 に示すダイアログを表示します。
このダイアログを使用して、新しい定義の追加、削除あるいは既存の定義を編集す ることができます。定義を追加する場合には、以下を入力します。
作成時に設定されない属性は、後で設定することができます。たとえば、定義のテ ストおよびデバッグは、定義のアイコンをデザインする前に実行できます。
「仮設定」を使用して、現在選択されているウィジェットのダイアログ上にあるフ ィールドのいくつかを自動的に設定することができます。
定義が相対ファイル名 (/ で始まらない名前) で指定されている場合、Sun WorkShop Visual はファイル名の前にベースディレクトリを追加します。ベースディレクトリが指定されていない場合は、定 義デザインファイルを含んでいるディレクトリが使用されます。
ベースディレクトリを指定するには、「定義を編集」ダイアログを表示して「ベー スディレクトリ」をクリックし、新しいディレクトリを選択して「了解」をクリックします。すると、新し いベースディレクトリが定義ファイルに保存され、Sun WorkShop Visual の現在のセッションに即座に適用されます。現在のデザインが既存の定義のインスタンスを含んでいる場合 、ベースディレクトリを変更することはできません。
定義内にあるウィジェットは凍結されています。したがって、ウィジェットの追加 または削除、名前の変更、配置エディタでのコンストレイントの設定、リソースのリセットは、行うことが できません。定義を変更するためには、一時的に定義を解除する必要があります。定義を変更する必要があ る場合には、以下に示す手順に従って操作を実行してください。
3. ウィジェットメニューをプルダウンし、「定義」トグルをオフにします。
トグルをオフにすると、定義にあるウィジェットの凍結が解除されるため、必要に 応じた変更、修正を行うことができます。
定義を変更すると、その定義を使用するすべてのデザインファイルに影響がありま す。定義を使用するデザインを開くたびに、Sun WorkShop Visual は定義を含むファイルを開き、これら両方のファイルからの情報を組み合わせます。定義が変更されると、 Sun WorkShop Visual は、変更前の定義を使用していたデザインが新しい定義を受け入れるように試みます。
受け入れられない変更がある場合には、Sun WorkShop Visual はエラーメッセージを表示し、デザインの不適合部分を一時的に Sun WorkShop Visual のクリップボード・ファイルに保存します。以下の方法のいずれかで、不適合を解決します。
定義のインスタンスは、パレットの適切なボタンをクリックするだけで作成できま す。インスタンスはカラー背景で表示されます。
定義とインスタンスは、それぞれに個別のデザインとして作成されなければなりま せん。Sun WorkShop Visual 内では定義とインスタンスは同一のデザインの中に存在していますが、それぞれに対するコードが個別のコ ードでなければ、コンパイルは行われません。
定義はそのファミリごとに、ウィジェットパレット上でまとめられます。ウィジェ ットパレットで定義の上にあるオプションメニューを使用すると、現在表示されているファミリを変更する ことができます。定義のファミリを指定する方法の詳細は、「定義ファイルの編集」を参照してください。
定義のインスタンス作成は、構造 (C 構造体または C++ クラス) のインスタンス作成に対応しています。変更が生成されるコードに反映される場合に限り、インスタンスを 作成した後で変更を行うことができます。たとえば、ウィジェットがアクセス可能である (例: C++ の場合、ウィジェットに名前があり、適切なアクセスモードを持っている) 場合にのみ、ウィジェットにリソースを設定したり、あるいはウィジェットに子を追加することが可能です 。ウィジェットの除去、あるいはその名前の変更を行うことはできません。ただし、ルートウィジェットは 例外です。インスタンスのルートウィジェットは常に (メンバー関数 xd_rootwidget() を介して) アクセス可能であるため、常に変更することができます。
定義から派生した新しい構造を作成すると役に立つ場合が多くあります。派生構造 を作成するには、コアリソースダイアログのコード生成ページにある「構造」オプションを設定します。派 生構造は、定義と同じ値にのみ設定することができます。つまり、C 構造体から C++ クラスを派生させることはできません。
定義のインスタンスを含むデザインから生成されたコードをコンパイルするには、 定義コードともリンクする必要があります。これを行うには次の 2 つの方法があります。
定義コードを含むライブラリをインスタンスコードとリンクさせるには、まず定義 のコードをライブラリにコンパイルします。通常、UNIX または C や C++ では、次の方法でコンパイルします。
make <definitioncode>.o
ar r <definitionlib>.a <definitioncode>.o
定義のインスタンスをコンパイルするもう 1 つの方法として、定義、定義のインスタンス、対応するメークファイルを同じディレクトリに生成する方法 があります。Sun WorkShop Visual では、定義とインスタンスの両方が同じアプリケーションにコンパイルされるようにメークファイルを構成 することができます。以下に、その手順を示します。
3. 「メークファイル・オプション」 ダイアログの 「新規メークファイル」 と 「メークファイル・テンプレート」 トグルをオンにします。
7. 「メークファイル・オプション」 ダイアログの 「新規メークファイル」 トグルをオフにして、「メークファイル・テンプレート」 トグルはオンのままにしておきます。
8. 「コードオプション」 ダイアログで、「リンク」 を「生成しない」 (リンク関数は生成済みなので、2 回目の生成ではエラーになる) に設定します。
9. コード、外部宣言ファイル、メークファイル (必要であればリソースも) を生成します。
定義についての情報を記録して、他の開発者にその内容を伝えるために、定義に対 してのオンラインヘルプをつけることができます。 <Tab> と矢印キーを使用して、定義のアイコンやボタンに移動し、 <osfHelp> (通常は <F1> ) を押すと、オンラインヘルプが Sun WorkShop Visual インターフェース内で呼び出されます。
ヘルプファイルは Sun WorkShop Visual ヘルプディレクトリのサブディレクトリに保存されています。
ヘルプディレクトリは helpDir リソースにより決定します。デフォルトでは、 $VISUROOT/lib/locale/${ LANG }/help となっています。
VISUROOT は、Sun WorkShop Visual のインストールディレクトリです。 LANG は使用するロケールで、デフォルトでは「 C 」です。