この章では、Sun WorkShop Visual の C++ コード生成機能を使用してアプリケーションに構造を追加する方法、および C++ クラスに対応する再使用可能なウィジェット階層の作成方法を説明します。これらの再使用可能階層は定義 と呼ばれ、ウィジェットパレット上に表示されます。また、他のウィジェットと同様 3 階層に追加することができます。この章では基本的には C++ について説明していますが、コールバック・メソッドの節を除き、ほとんどの項目は C での構造コード生成にも適用することができます。相違点がある場合は、注釈で説明しています。
本章の内容をよりよく理解するには、Sun WorkShop Visual を起動し、説明されている操作手順を実際に実行してみることをお勧めします。
構造化コード生成の詳細については、第 8 章「構造化コード生成および再使用可能な定義」を参照してください。
Sun WorkShop Visual の C++ クラスは、子を持つどのようなウィジェットにも対応します。ウィジェットを C++ クラスとして指定すると、Sun WorkShop Visual はそのウィジェット、および名前が付けられている子孫ウィジェットをデータメンバーとして使用してクラ スを生成します。このクラスは、データメンバーおよびメンバー関数を追加して拡張することができ、その 結果、階層全体に関連する属性を一箇所に集めることができます。
以下の操作手順を使用して、メニューバーウィジェットを含むウィジェット階層を 作成し、その後メニューバーを C++ クラスとして指定します。この例は、Microsoft Windows のコード生成とは互換性がないことに注意してください。
1. 同一の親ディレクトリを持つ新しいディレクトリ libmenu と cmd を作成します。
2. ディレクトリ libmenu へ移動して、Sun WorkShop Visual を起動します。
3. 図 9-1 に示すようなウィジェット階層を構築します。
明示的に名前が付けられたウィジェットだけがクラスのメンバーとして作成されま す。名前が付けられていないウィジェットは、それらを作成する関数に対して局所的になります。ウィジェ ットの命名により、そのクラスのメンバー関数から直接アクセスすることができるようになります。それら のウィジェットはデフォルトで限定公開メンバーであるため、任意の派生クラスのメンバー関数からもアク セスすることができます、
4. 図 9-1 に示すようにウィジェットの変数名を設定します。
5.
カスケードボタンおよびプッシュボタンに対しての「ラベル」リソースをそれぞれ次の文字列に設定します
。
File、Help、New、Exit
6. シェルのリソースパネルを使用してシェルウィジェットをアプリケーションシェルとして指定し、シェルウ ィジェットのタイトルを「Demo」に指定します。
これで階層の例が完成しました。では次に、メニューバーを C++ クラスとして指定します。
7. ウィジェット階層内でメニューバーウィジェットを選択します。
8. コアリソースパネルの「コード生成」のページを表示します。
9. 図 9-2 に示すように、「構造」オプションメニューから「C++/Java クラス」を選択します。
Sun WorkShop Visual
は、デフォルトで、ウィジェット名をデフォルトのクラス名およびインスタンス名として使用するため、
生成された menubar_c クラスは、クラスウィジェット ( menubar ) および名前が付いているすべての子孫ウィジェットをメンバーとして含みます。デフォルトでは、これらの ウィジェットは限定公開メンバーとなっていますが、コアリソースパネルを使用して任意のウィジェットの アクセス制御を変更することができます。以下の操作手順に従って、ヘルプメニューをクラスの公開メンバ ーにします。
図 9-3 に「コード生成」のページを示します。
クラスに対して生成されたコードは、生成された外部宣言ファイルにあるクラス宣 言と、C++ の基本コードファイルにある実装で構成されます。これらのファイルを生成するには、以下のように操作を 行います。
1. 「コード生成」ダイアログを表示して、「言語」メニューで「C++」が選択されていることを確認します。< /P>
2. 「コード」テキストフィールドに menubar.cpp と入力して、「生成」トグルをオンにします。
3. 「外部宣言」テキストフィールドに menubar.h と入力して、「生成」トグルをオンにします。
4. 「メインプログラム」テキストフィールドに menubar.cpp と入力して、「生成」トグルをオンにします。
5. 「メークファイル」テキストフィールドに Makefile と入力して、「生成」トグルをオンにします。
6. 「メークファイル」テキストフィールドの横にある「オプション」ボタンを押します。
7. 「メークファイル・オプション」ダイアログで「新規メークファイル」と「メークファイル・テンプレート 」を両方オンにして、「了解」ボタンを押します。
8. 「コード」テキストフィールドの横にある「オプション」ボタンを押します。
図 9-4 に示す「C++コードのオプション」ダイアログが表示されます。
9. 図 9-4 で示すように「ヘッダーファイルをインクルード」テキストフィールドに menubar.h と入力して、「了解」ボタンを押します。
10. 「コード生成」ダイアログの下の方にある「オプション」ボタンを押して、オプションを図 9-5 で示すように設定して、「了解」ボタンを押します。「文字列」リソースがコードに生成されるように設定 されていることを確認してください。
C++ 外部宣言ファイルである menubar.h には、クラスに対しての宣言が含まれています。
...
class menubar_c: public xd_XmMenuBar_c {
public:
virtual void create (Widget parent, char *widget_name =
NULL);
Widget help;
protected:
Widget menubar;
Widget file;
Widget filemenu;
Widget fm_new;
Widget fm_exit;
};
typedef menubar_c *menubar_p;
...
このメニューバーに対しての新しいクラスは、既存のクラスである xd_XmMenuBar_c を基底クラスとしています。メニューバーおよび名前の付いているその子孫ウィジェットは、すでに公開と して指定した help ウィジェットを除いては限定公開メンバーです。
C++ 基本コードファイルである menubar.cpp は、新しいクラスに対しての作成関数を含んでいます。この関数は、メニューバーウィジェットおよびその 子孫を作成します。これらは、 menubar_c のコンストラクタでは作成されません。このため、クラスのインスタンスを作成した後にウィジェットを作 成することが可能になります。
...
#include <menubar.h>
...
void menubar_c::create (Widget parent, char *widget_name)
{
Widget children[2];/* マネージする子 */
Arg al[64]; /* 引数リスト*/
register int ac = 0;/* 引数の個数 */
XmString xmstrings[16];/* XmStrings の一時記憶領域 */
if ( !widget_name )
widget_name = "menubar";
menubar = XmCreateMenuBar ( parent, widget_name, al,
ac );
_xd_rootwidget = menubar;
xmstrings[0] = XmStringCreateLtoR("File",
(XmStringCharSet)XmFONTLIST_DEFAULT_TAG);
XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
file = XmCreateCascadeButton ( menubar, "file", al,
ac );
ac = 0;
...
children[ac++] = file;
children[ac++] = help;
XtManageChildren(children, ac);
ac = 0;
}
menubar.cpp ファイルには、階層全体に対しての作成関数も含まれています。この関数は、クラス外の任意のウィジェッ トを作成します。この例ではシェルだけです。そして、 menubar_c クラスのインスタンスを作成し、クラスのウィジェットメンバーを作成するための menubar_c::create() を呼び出します。
void create_shell (Display *display, char *app_name, int app_argc, char **app_argv)
{
Widget children[1]; /* マネージする子 */
Arg al[64]; /* 引数リスト */
register int ac = 0; /* 引数の個数 */
XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++;
XtSetArg(al[ac], XmNtitle, "Demo"); ac++;
XtSetArg(al[ac], XmNargc, app_argc); ac++;
XtSetArg(al[ac], XmNargv, app_argv); ac++;
shell = XtAppCreateShell ( app_name, "XApplication",
applicationShellWidgetClass, display, al, ac );
ac = 0;
menubar = new menubar_c;
menubar->create ( shell, "menubar" );
XtManageChild ( menubar->xd_rootwidget());
}
コードの生成時に「メインプログラム」トグルを設定したため、 menubar.cpp にはメインプログラムも含まれます。したがって、アプリケーションは現状のまま構築することができます 。
Sun WorkShop Visual が生成した C++
コードは、そのまま簡単に構築することができます。ただし、生成されたクラスが派生する
xd_XmMenuBar_c などの基底クラスが使用できることが必要です。
$VISUROOT/src/xdclass/lib
ディレクトリは、デフォルト基底クラスに対してのソースを含んでいます。
$VISUROOT/src/xdclass/h
は、ヘッダーファイルを含んでいます。
libxdclass.a ライブラリが構築されていない場合は、以下の手順に従って、供給されるメークファイルを使用するライブ ラリを構築します。
1. Sun WorkShop Visual インストールディレクトリ中の src/xdclass/lib ディレクトリに移動します。
make が終了すると、libxdclass.a ライブラリが使用可能となります。
これまで、例としてウィジェット階層をクラスとして指定する方法と、生成される コードの形式を見てきました。現段階では、ウィジェット階層をクラスとしては活用していません。
注 - この節は、C++ プログラミングに特に関連している説明です。C の枠組みの中では、従来のコールバックの機構を使用することができるため、C++ プログラミングを行わないユーザーは、「定義の作成」に進んでください。
Sun WorkShop Visual では、クラスメンバー関数をコールバック関数として指定することができる、単純なメカニズムを提供して います。これらのメカニズムをコールバック・メソッドと呼びます。使用する技術については、「コールバック・メソッド」で詳しく説明しています。
コールバック・ダイアログを使用すると、イベントに対する応答で呼び出されるメ ンバー関数を指定することができます。特定のウィジェットに対してコールバック・メソッドを指定すると 、呼び出されるメソッドは、そのウィジェットの最も近くにあるクラス指定されたウィジェット (たいていはウィジェットそのもの) に属します。たとえば、メニューバー例にあるメニューボタン上のコールバック・メソッドは、 menubar_c クラスのメンバー関数を呼び出します。
以下の手順を使用して、 fm_new ボタンのクラスメソッドを宣言します。
1. ウィジェット階層で fm_new ボタンを選択します。
2. 「ウィジェット」メニューから「コールバック」を選択するか、ツールバーの「コールバック」ボタンを押 して、コールバックダイアログを表示します。
3. 「コールバックのリスト」から「活性化 (activate)」を選択します。
4. 「メソッドの名前」フィールドに次のように入力します。
OnNew
これにより、図 9-6 に示すように、局所的メソッドのリストに OnNew が追加されます。
これは、メンバー関数 menubar_c::OnNew() をボタン fm_new の活性化コールバックを扱うメソッドとして指定します。この作業を行う際、ユーザーがまだ宣言を行なっ ていない場合には、Sun WorkShop Visual は親ウィジェットである menubar 上でもメソッドの宣言を行います。
同様に、 fm_exit ボタンにコールバック・メソッドを入力します。
6. ウィジェット階層で fm_exit ボタンを選択します。
7. 「コールバック」ダイアログで「活性化 (activate)」を選択します。
クラスには menubar_c::OnNew() と menubar_c::OnExit() という 2 つのコールバック・メソッドが存在することになります。
クラス内からコールバック・メソッドを使用すると、Sun WorkShop Visual は 2 つの別のメンバー関数に対し、ひとつに対しては完全な実装を、もうひとつに対してはスタブという宣言を 生成します。
1. 「コード生成」ダイアログを表示して、「言語」オプションが「C++」に設定されていることを確認します 。
2. 「スタブ」とラベルの付いたテキストボックスに menubarS.cpp と入力して、「生成」トグルをオンにします。
3. 「メークファイル・オプション」ダイアログを表示します。
4. 「新規メークファイル」トグルをオフに、「メークファイル・テンプレート」トグルをオンにして、「了解 」ボタンを押します。
menubar.h 内のクラス宣言を見てください。各コールバック・メソッドに対して 2 つの新しいメンバー関数が追加されています。
class menubar_c: public xd_XmMenuBar_c {
public:
...
static void OnExit( Widget, XtPointer, XtPointer );
virtual void OnExit( Widget, XtPointer );
static void OnNew( Widget, XtPointer, XtPointer );
virtual void OnNew( Widget, XtPointer );
};
これらの関数の静的バージョンのみが、 Xt コールバックが予定している引数リストを持ちます。したがって、Xt がコールバック・メソッド menubar_c::OnNew() を呼び出す場合には、C++ コンパイラは引数リストにもとづいて静的バージョンを選択します。
menubar の作成関数には以下に示す行が含まれていることに注意してください。
XtAddCallback (fm_new, XmNactivateCallback, OnNew, (XtPointer)
this);
静的関数に対してのコードは、 menubar.cpp にも生成されます。この関数は、クライアントデータとして渡されるインスタンス・ポインタを使用して、 単純に非静的な仮想メンバー OnNew(Widget, XtPointer) を呼び出します。
void menubar_c::OnNew( Widget widget, XtPointer client_data, XtPointer call_data )
{
menubar_p instance = (menubar_p) client_data;
instance->OnNew ( widget, call_data );
}
ユーザーは、非静的仮想メンバー関数 OnNew(Widget, XtPointer) に対するコードを書く必要があります。この関数に対してのスタブ (原型) は、 menubarS.cpp に生成されます。
void
menubar_c::OnNew (Widget w, XtPointer xt_call_data )
{
XmAnyCallbackStruct *call_data = (XmAnyCallbackStruct *)
xt_call_data;
}
Sun WorkShop Visual は、このパターンにもとづいて、階層内で使用されるすべてのコールバック・メソッドに対してコードを生 成します。この例では、類似したコードが OnExit() に対して生成されます。
OnNew() および OnExit() は、 fm_new および fm_exit プッシュボタンから呼び出されますが、関数は menubar_c クラスのメソッドです。これは、クラス内でウィジェットの動作を定義するすべてのコールバック関数は 1 ヵ所に保存されていることを意味します。また、すべてのコールバック関数はクラスのインスタンスデータ へのアクセス権を持っており、それを使用して情報を共有することができます。
アプリケーション動作は、コールバック・メソッドを実装することにより追加され ます。Sun WorkShop Visual の編集機能を使用して、コールバック・メソッドを編集することもできます。以下に示す手順で、 OnExit() メソッドを実装します。
2. 「コールバック」ダイアログを表示して、 OnExit() コールバックを選択します。
<現作業ディレクトリ> /libmenu にある menubarS.cpp という名前のファイルが開きます。このファイルに記述された OnExit メソッドにコードを追加することができます。コールバックの編集についての詳細は、「Sun WorkShop Visual 内でのコールバックコードの編集」を参照してください。
void
menubar_c::OnExit (Widget w, XtPointer xt_call_data )
{
XmAnyCallbackStruct *call_data = (XmAnyCallbackStruct*)
xt_call_data;
exit(0);
}
コールバック・メソッドには、アクセスレベルおよび純粋仮想か否かという 2 つの属性があります。アクセスレベルは、そのメソッドが派生クラスおよび外部コードからアクセスできる かどうかを決定します。また、メソッドは、基底クラスでの実装を持たないことを示す純粋仮想として指定 することができます。詳細は、第 8 章「構造化コード生成および再使用可能な定義」の 「C++ クラス」を参照してください。
属性はコールバックが最初に指定される時には、デフォルトに設定されています。 属性の初期設定は、クラスの祖先を持つ、またはクラスである任意のウィジェットで行うことができます。 しかし、その変更はクラスのルートウィジェット上で行われます。たとえば、クラス menubar_c の OnNew() コールバック・メソッドは、 menubar ウィジェットそのものを使用してのみ編集することができます。
1. ウィジェット階層で、メニューバーウィジェットを選択します。
2. 「ウィジェット」メニューで「メソッド宣言」を選択し、「メソッド宣言」ダイアログを表示します。
クラスに対して宣言されたコールバック・メソッドのリスト (特定のイベントに 対して呼び出されるメソッドのリストではない) が表示されます。このパネルを使用する と、コールバック・メソッドの編集、およびそのクラスのイベントによってではなく派生ク ラスにより呼び出される可能性のあるメソッドを宣言することができます。
3. メソッド OnNew() を選択し、「純粋仮想」トグルを設定します。
4. 「追加/更新」ボタンをクリックして変更を適用します。図 9-7 に示すような結果になります。
純粋仮想メンバー関数に対する実装は、無効ではありませんが行う必要はありませ ん。
6. スタブファイル menubarS.cpp を temp.cpp にコピーします。
7. スタブファイル menubarS.cpp を編集して OnNew() に対してのスタブ (例: 中括弧で囲まれたコード) を削除します。
C++ コンパイラは、次のようなエラーメッセージを発します。
"menubar.cpp" 100 行目: 抽象クラス menubar_c に対して変数を作成することはできません。
menubar_c クラスが純粋仮想関数を含んでいるためインスタンス化することはできません。したがって、エラーが発生 することになります。この時点では、このクラスは基底クラスとしてのみ使用することができます。本章の 後半では、このクラスを派生クラスの基礎として使用します。
この節および次の「派生クラスの作成」では、Sun WorkShop Visual の生成されたクラスにメンバーを追加する技術を説明します。ここで説明する技術は以下の 2 つです。
少数のメンバーを追加する最も簡単な方法としては、プレリュード機能を使用しま す。この機能を使用すると、Sun WorkShop Visual にコードの断片を入力することができ、また、それらを生成されたコードに渡すこともできます。
注 - Sun WorkShop Visual の編集機能を使用して、生成されたコードに直接プレリュードを入力することもできます。詳細は 「生成されたファイルのカスタマイズ : プレリュード」を参照してください。
次の例では、コードを生成する前にコードプレリュードダイアログを使用してプレ リュードを追加します。
1. ウィジェット階層でメニューバーウィジェットを選択します。
2. ウィジェットメニューをプルダウンして、「コードプレリュード」を選択します。
図 9-8 に示すダイアログが表示されます。
コードプレリュード・ダイアログを使用すると、少数のコードを簡単に挿入するこ とができます。実質的な機能を追加するためには、多くの場合、生成されたクラスから派生する新しいクラ スを作成する方が良いでしょう。2 つのクラス間の論理的な違いを使用して、メンバーの追加および仮想関数の実装を行うことができます。 P>
デフォルトでは、ルートウィジェットの変数名をもとに C++ クラスの名前が決まります。したがって、ウィジェット menubar のクラスは menubar_c になります。
class menubar_c: public xd_XmMenuBar_c {
...
};
クラスのインスタンスを作成するためにコードを生成する場合は、同じ名前が使用 されます。
menubar = new menubar_c;
生成されたクラスをある名前で宣言し、別の名前でインスタンスを作成するように 、その動作を変更することができます。たとえば次のようにします。
menubar = new mymenubar_c;
この変更を行うためには、コアリソースパネルにあるコード生成ページの「インス タンス名」を使用します。
1. ウィジェット階層でメニューバーウィジェットを選択します。
2. コアリソースパネルの「コード生成」ページを表示します。
3. 「インスタンス名」を mymenubar_c に設定します (図 9-9 参照)。
元のクラスである menubar_c は、以前とまったく同様に宣言されています。しかし、Sun WorkShop Visual がクラスのインスタンスを作成するためにコードを生成する場合には、「インスタンス名」での名前が使用 されます。
menubar = new mymenubar_c;
Sun WorkShop Visual は、 mymenubar_c クラスに対してコードを生成しません。ユーザーは、クラスおよび含まれるメソッドを実装するためのコー ドを宣言する、ヘッダーファイルを提供する必要があります。新しいクラスは、 menubar_c から派生しなければならないことを除いては、何ら制約を受けていません。この例の場合は、以下に示すコ ード例を使用します。
#ifndef _mymenubar_h
#define _mymenubar_h
#include <menubar.h>
class mymenubar_c: public menubar_c {
public:
// コンストラクタ
mymenubar_c();
// 継承される純粋仮想に対して実装を提供する
void OnNew(Widget, XtPointer);
};
#endif
新しいクラスは menubar_c から派生するため、Sun WorkShop Visual でそのクラスに対して宣言したすべてのウィジェットメンバーおよびメンバー関数が継承されます。新しい メンバーは任意の数だけ追加することができます。ここでは、コンストラクタ関数と OnNew() 仮想コールバック・メソッドの実装を追加します。
#include <mymenubar.h>
mymenubar_c::mymenubar_c()
{
modified = TRUE;
}
void
mymenubar_c::OnNew(Widget, XtPointer)
{
// 修正されたフラグをリセットする
if (modified)
modified = FALSE;
}
これで、クラスに対してのすべてのコードが完了します。生成された C++ コードモジュール mymenubar.cpp は、派生クラス mymenubar_c に対してのヘッダーファイルを組み込む必要があります。これは、C++ の「コード生成」ダイアログにある「ヘッダーファイルをインクルード」を使用して実行することができま す。
4. 「コード」ファイル名フィールドの横にある「オプション」ボタンを押します
5. 「ヘッダーファイルをインクルード」フィールドに mymenubar.h と入力して「ヘッダーファイルをインクルード」トグルをオンにし、「了解」ボタンをクリックします。 P>
図 9-10 に、新しいファイル名を表示した「コードオプション」ダイアログを示します。
XD_CC_SOURCES=mymenubar.cpp
XD_CC_OBJECTS=mymenubar.o
mymenubar.o:mymenubar.cpp
$(CCC) $(CCFLAGS) $(CPPFLAGS) -c mymenubar.cpp
この時点で、「ファイル」メニューの「新規」ボタンを押すと、アプリケーション はクラス mymenubar_c を使用し、その OnNew() メソッドを呼び出します。この動作が正しく行われることを確認するには、 mymenubar_c::OnNew() を拡張してメッセージを出力します。
コンストラクタに対しての実際の引数を、クラス名と一緒に供給することができま す。たとえば、「インスタンス名」文字列を「mymenubar_c ("Hello World")」に設定すると、Sun WorkShop Visual は次のようなコードを生成します。
menubar = new mymenubar_c ( "Hello World" );
ウィジェットの階層がクラスとしていったんカプセル化されると、それを定義に変 換することにより他のデザインで再度使用することができます。定義は、Sun WorkShop Visual ウィジェットパレットに追加することができる、再使用可能なウィジェットのグループです。パレットから 定義を選択すると、その構造のインスタンスがデザイン内に作成されます。Sun WorkShop Visual がインスタンスを含んでいるコードを生成する場合、ウィジェットを作成するための定義の作成関数が呼び 出されます。
メニューバークラスを定義として指定するためには、以下のように操作します。
2. ウィジェットメニューをプルダウンして、「定義」トグルを設定します。
メニューバーウィジェットおよびその子孫が色付きの区画で囲まれ、定義を構成す ることを示します。
注 - 定義を含んでいるデザインは、パレットに追加する前に保存する必要があります。S un WorkShop Visual は、定義が使用されるごとに保存されたデザインファイルを使用します。単一のデザインファイル内には複 数の定義を持たせることができますが、各ファイルに定義をひとつだけ持たせておくと、追跡が簡単になり ます。
定義を作成すると、ウィジェットが定義内に凍結されます。凍結されたウィジェッ トのリソースパネルは使用できなくなるため、ウィジェットの追加またはウィジェット名の変更を行うこと はできません。定義を構成するウィジェットの変更は、一時的に定義を取り除くことによってのみ行うこと ができます。この作業は、定義を使用するデザインとの矛盾を発生させるおそれがあるので、十分な注意が 必要です。詳細は、第 8 章「構造化コード生成および再使用可能な定義」、「定義の変更」を参照してください。
この節では、新しい定義をウィジェットパレットに追加する方法を説明します。
図 9-11 に示すダイアログが表示されます。
このダイアログを使用して、すでに定義マークが付けられているウィジェットを新 しい定義として追加、定義を削除、あるいは既存の定義を編集をすることができます。定義を追加するには 、以下の情報を入力する必要があります。
その他の属性については、第 8 章「構造化コード生成および再使用可能な定義」の 「定義のオンラインヘルプ」を参照してください。
作成時に設定されない属性は、後で設定することができます。たとえば、定義のテ ストおよびデバッグは、そのアイコンをデザインする前に実行できます。
メニューバーに指定した「インスタンス名」の名前は、定義が使用されるごとに適 用されます。
アイコンは使用しなくても構いません。アイコンを指定しない場合は、ウィジェッ トパレットに追加される定義プッシュボタンのラベルとして、ルートウィジェットの名前が使用されます。 指定したアイコンファイルが存在しない場合は、定義のルートウィジェットの (Sun WorkShop Visual で使用している) アイコンファイルが、パレット上に表示されます。
Sun WorkShop Visual のピックスマップ・エディタを使用して、定義にするデザインのアイコンを作成することもできます。その 場合はウィジェット階層での選択を示すために使用される領域の色には「none」を使用します。ピックスマ ップエディタの詳細は 「ピックスマップ・エディタの使用」を、新しいウィジェットパレットの作成方法については 「パレットアイコン」を参照してください。
Sun WorkShop Visual リソースファイルを使用して、アイコンを指定することもできます。アイコンの指定を行うには、Sun WorkShop Visual リソースの名前を「アイコンリソース」フィールドに指定し、そのリソースを Sun WorkShop Visual リソースファイルにあるファイル名に設定します。
定義に対してのコードは、公開ヘッダーファイル (外部宣言ファイル) 内の宣言と、実装を含んでいるコードモジュールのふたつの部分で構成されます。インスタンスを含んでい るアプリケーションをコンパイルするために、コードモジュールが公開である必要はありません。ライブラ リにおいて、コンパイルされた形式で使用可能にすることができます。
定義に対してのコードだけ、つまりシェルまたは他のウィジェット、およびメイン プログラムを除いたコードだけを生成するには、以下の手順を使用します。
シェルウィジェットに対してコードが生成されないようにするためには、次のよう にします。
この操作の後、Sun WorkShop Visual は C++ クラス、関数またはデータ構造体として指定されていないシェルおよびシェルの子を無視します。コードは メニューバーおよびその子孫にのみ生成されます。
5. 「メインプログラム」に対する「生成」トグルをオフにします。
6. 「コード」、「スタブ」、および「外部宣言」に対する「生成」トグルがオンになっていて、外部宣言ファ イル名として menubar.h が指定されていることを確認します。
これにより、定義および対応するクラスのコード作成に必要な処理が完了し、アプ リケーションで使用できるようになります。この実装を再使用するには、ライブラリとして使うことが一般 的です。
make menubar.o
make menubarS.o
make mymenubar.o
ar r libmenu.a *.o
定義はパレット上のウィジェットと同様の方法で使用することができます。パレッ ト上のボタンをクリックすると、定義のインスタンスが作成されます。Sun WorkShop Visual は定義の階層をツリーにコピーします。ここで階層の修正および拡張を行うことができます。生成されたコ ードには、Sun WorkShop Visual がインスタンスを作成するための定義の作成関数の呼び出しを組み込みます。
menubar 定義を使用して新しいデザインを構築するには、以下のようにします。
2. シェル、メインウィンドウ、新しい menubar 定義のウィジェットパレットアイコンをクリックします。
新しい定義がウィジェットパレットに追加されて、手順 4 で指定したアイコンが作成されます。
これにより、図 9-12 に示すウィジェット階層が作成されます。
インスタンスの構成要素は、単一の項目を形成することを示す色付きのボックスで 囲まれています。ルートウィジェットを除くすべてのウィジェットには、元の定義で持っていた名前と同じ 名前が指定されます。ルートウィジェットには、<ウィジェットクラス> <n> 形式のデフォルト名が割り当てられます。コードの信頼性を高めるためにも、明示的な名前を割り当てます 。
3. インスタンスのルートウィジェット、 シェルおよびメインウィンドウ に、図 9-12 のように名前を付けます。
インスタンスを作成した後、生成されたコード内で変更を実行できる場合に限り、 インスタンスを変更することができます。たとえば、ウィジェットが公開アクセスを持っている場合はその ウィジェットへのリソースの設定、あるいは子の追加を行うことができます。ウィジェットの削除、名前の 変更はできません。しかし、ルートウィジェットは例外となります。インスタンスのルートウィジェットは メンバー関数 xd_rootwidget() を使用して呼び出すことができるため、常に修正することができます。
この例では、定義のすべての構成要素は help ボタンを除いて限定公開となっています。これは、 help ボタンのラベルのみが変更可能であることを意味します。同様に、 help ボタンの下に別のウィジェットを追加することができますが、 filemenu メニューには追加することはできません。
1. ウィジェット階層内で help ウィジェットを選択します。
2. ウィジェットパレットでメニューアイコンをクリックし、プッシュボタンアイコンをクリックします。
help カスケードボタンの下に選択項目を 1 つだけ持つメニューが追加されます。
3. ウィジェット名を図 9-13 に示すように設定します。
現在、ユーザーは定義内の他のウィジェットを修正することはできません。たとえ ば、 filemenu にボタンを追加することはできません。しかし、定義からのサブクラスを作成すると、公開ウィジェットに 加えて限定公開ウィジェットも修正することができます。その方法は、次の「派生クラスの作成」で説明し ます。
定義に対応しているクラスのほとんどのメンバーは限定公開であるため、定義のイ ンスタンスでそれらを呼び出すことはできません。これを解決するためには、次の 2 通りの方法があります。
2 番目の方法は、カプセル化された構造をよりよく維持することができます。また、コールバック・メソッド を活用することもできます。
1. ウィジェット階層内でメニューバーウィジェットである appmenu を選択します。
2. コアリソースパネルの「コード生成」ページを表示します。
3. 「構造」オプションメニューから「C++ クラス」を選択して「適用」をクリックし、リソースパネルを閉じます。
menubar ウィジェットは図 9-14 に示されるように、クラスとして指定されます。このクラスは定義に対応するクラスから派生されます。 P>
クラスのメンバー関数は、 mymenubar_c の限定公開メンバーを呼び出すことができるため階層内の任意の場所にウィジェットを追加することができ ます。
4. ウィジェット階層内で filemenu ウィジェットを選択します。
5. メニューに 2 個のプッシュボタンを追加し、「Open...」および「Save...」というラベルを付けます。
6. 新しいボタンの変数名を fm_open および fm_save に設定します。
7. マウスボタン 1 を使用して、新しいボタンを図 9-15 に示す位置までドラッグします。
定義の順序は変更できません。新しいウィジェットを定義に追加することはできま すが、すでに定義内の一部であるウィジェットを移動することはできません。
9. 「ウィジェット」メニューから「コールバック」を選択するか、ツールバーの「コールバック」ボタンを選 択して、コールバックダイアログを表示します。
10. コールバックリストから「活性化 (activate)」を選択します。
11. 「メソッドの名前」フィールドに次のように指定します。
OnOpen
13. 上述の手順を繰り返し、 fm_save に対しての「活性化 (activate)」コールバック・メソッドを OnSave に設定します。
この方法は C 構造体に対しても有効です。Sun WorkShop Visual は定義の構造体の拡張である新しい構造体を生成します。
メニューバーに対応するクラス appmenu_c は、継承される OnNew() 、 OnExit() 、および appmenu_c 自体により定義される OnOpen() 、 OnSave() という 4 種類のコールバック・メソッドを持っています。しかし、継承されるメソッドは書き換えることができるた め、派生クラスに基底クラスとは異なる動作を持たせることができます。
OnExit() と OnNew() が menubar_c から継承されるのに対し、 OnSave() と OnOpen() は appmenu_c に局所的です。継承されたメソッドは角括弧 [ ] で囲まれて表示されます。
書き換えられたメソッドを実装するには、Sun WorkShop Visual が生成したスタブを完成させます。
1. 「コード生成」ダイアログを表示して、「言語」オプションが「C++」に設定されていることを確認します 。
2. 「ディレクトリ」フィールドに、 /u/mgs/TUTORIAL/cmd などのようにディレクトリ cmd へのフルパス名を指定します。
これは、コードの生成先となるディレクトリを指定するための手順です。
3. 「コード」テキストフィールドに app.cpp と入力して、横にある「生成」トグルをオンにします。
4. 「スタブ」テキストフィールドに appS.cpp と入力して、横にある「生成」トグルをオンにします。
5. 「外部宣言」テキストフィールドに app.h と入力して、横にある「生成」トグルをオンにします。
6. 「メインプログラム」テキストフィールドに app.cpp と入力して、横にある「生成」トグルをオンにします。
7. 「メークファイル」テキストフィールドに Makefile と入力して、横にある「生成」トグルをオンにします。
8. 「メークファイル・オプション」ダイアログで「新規メークファイル」トグルと「メークファイル・テンプ レート」トグルを両方オンにして、「了解」ボタンを押します。
9. 「コード」テキストボックスの横にある「オプション」ボタンを押します。
10. 「ヘッダーファイルをインクルード」テキストフィールドに app.h と入力し、トグルをオンにして「了解」ボタンを押します。
11. 「コード生成」ダイアログの最下部にある「オプション」ボタンを押して、「コードオプション」ダイアロ グのオプションを 図 9-17 のとおりに設定します。
...
#include <iostream.h>
void
appmenu_c::OnExit (Widget w, XtPointer xt_call_data)
{
...
if (modified)
XBell(XtDisplay(w), 100);
else
exit(0);
}
void
appmenu_c::OnSave (Widget, XtPointer xt_call_data)
{
...
cout << "Saving..." << endl;
modified = FALSE;
}
void
appmenu_c::OnOpen (Widget, XtPointer xt_call_data)
{
...
cout << "Opening..." << endl;
modified = TRUE;
}
この OnExit() の実装は、定義における実装を書き換えます。関数 XBell() は X サーバー上でベルを鳴らします。 OnSave() と OnOpen() は、適切なメッセージを出力し、 modified フラグを更新するだけのダミーの関数です。
アプリケーションのメニューバーの機能は、現段階では以下のようになっています 。
15. メークファイルの中の「 MOTIFLIBS= 」で始まる行と「 CFLAGS= 」で始まる行を以下のように変更します。
MOTIFLIB=-lmenu -lXpm -lXm -lXt -lX11
CFLAGS=-I. ${XINCLUDES} -I${XPMDIR} -I../libmenu \
-L../libmenu
定義の構成要素であるウィジェットのリソース値は、明示的に設定することも、リ ソースファイルに指定することもできます。定義のリソースファイルを指定するとそのファイルは、その定 義のインスタンスを含んでいるすべてのデザインのリソースファイルにインクルードされます。
ここまでの例では、すべてのリソースは明示的に設定されていました。以下の手順 を使用して、リソースファイル中の文字列リソースを使用するようにメニューバー定義を再生成してみまし ょう。
1. libmenu ディレクトリのデザインファイル menubar.xd を開きます。
2. 「コード生成」ダイアログを表示して、「言語」メニューが「C++」に、「ディレクトリ」が libmenu ディレクトリに設定されていることを確認します。
3. 「コード生成」ダイアログから「コードオプション」ダイアログを表示して、「文字列」オプションメニュ ーを「リソースファイル」に設定し、「了解」ボタンを押します。
ここで、文字列リソースを含んでいるリソースファイルを生成します。
4. 「コード生成」ダイアログで、「 X リソース」テキストボックスに menubar.res と入力して、横にある「生成」トグルをオンにします。
5. 「コード」テキストボックスの横にある「生成」トグルがオンに、「メインプログラム」および「メークフ ァイル」の横にある「生成」トグルがオフになっていることを確認します。
8.
libmenu
ディレクトリで、次にように入力します。
make clean
9. 手順 10 と同じ手順でライブラリを再度構築します。
前節では、文字列リソースがリソースファイルに保存されるように、定義の生成さ れたコードを変更しました。次に、 menubar 定義を編集してリソースファイルを指定します。
../libmenu/menubar.res
定義に対してリソースファイルを指定すると、Sun WorkShop Visual は定義のインスタンスを含むすべてのデザインにそのファイルをインクルードします。リソースファイルを 読み取る Xlib メカニズムは、指示文を解釈し、定義に対するリソースファイルの検索に使用します。以下の手順を使用し て、この動作を app.xd アプリケーションで試してみます。
1. cmd ディレクトリのデザインファイル app.xd を開きます。
2. 「コード生成」ダイアログを表示して、「言語」メニューが「C++」に設定されていることを確認します。< /P>
3. 「 X リソース」テキストボックスに app.res と入力して、横にある「生成」トグルをオンにします。
4. 「コード」および「メインプログラム」テキストボックスの横にある「生成」トグルを、両方オンにします 。
5. 「スタブ」、「外部宣言」、および「メークファイル」の横にある「生成」トグルがすべてオフになってい ることを確認します。
6. 「コード生成」ダイアログから「コードオプション」ダイアログを表示して、「文字列」オプションメニュ ーを「リソースファイル」に設定し、「了解」ボタンを押します。
アプリケーションに対する X リソースファイルには、以下の指令が含まれています。
! Generated by Sun WorkShop Visual
#include "../libmenu/menubar.res"
Xlib は、この #include 指令を、アプリケーションリソースファイルを含んでいるディレクトリへの相対的なパス名の指定として解 釈します。詳細は、Xlib の資料を参照してください。
8. 次のように入力して、プログラムを構築します。
make
9. 環境変数 XENVIRONMENT をリソースファイル名に設定します。
設定するための構文は、使用するシェルの種類によって異なります。以下の例を参 考にしてください。C シェルの場合は、次のように入力します。
setenv XENVIRONMENT app.res
XENVIRONMENT=app.res; export XENVIRONMENT
サン・マイクロシステムズ株式会社 Copyright information. All rights reserved. |