前へ 次へ 目次 文書セット ホーム


第 9 章

 

C++ コードの学習


はじめに

この章では、Sun WorkShop Visual の C++ コード生成機能を使用してアプリケーションに構造を追加する方法、および C++ クラスに対応する再使用可能なウィジェット階層の作成方法を説明します。これらの再使用可能階層は定義 と呼ばれ、ウィジェットパレット上に表示されます。また、他のウィジェットと同様 3 階層に追加することができます。この章では基本的には C++ について説明していますが、コールバック・メソッドの節を除き、ほとんどの項目は C での構造コード生成にも適用することができます。相違点がある場合は、注釈で説明しています。

本章は、以下のような形式で説明を進めていきます。

本章の内容をよりよく理解するには、Sun WorkShop Visual を起動し、説明されている操作手順を実際に実行してみることをお勧めします。

構造化コード生成の詳細については、第 8 章「構造化コード生成および再使用可能な定義」を参照してください。

C++ クラスの作成

Sun WorkShop Visual の C++ クラスは、子を持つどのようなウィジェットにも対応します。ウィジェットを C++ クラスとして指定すると、Sun WorkShop Visual はそのウィジェット、および名前が付けられている子孫ウィジェットをデータメンバーとして使用してクラ スを生成します。このクラスは、データメンバーおよびメンバー関数を追加して拡張することができ、その 結果、階層全体に関連する属性を一箇所に集めることができます。

C++ クラスの指定

以下の操作手順を使用して、メニューバーウィジェットを含むウィジェット階層を 作成し、その後メニューバーを C++ クラスとして指定します。この例は、Microsoft Windows のコード生成とは互換性がないことに注意してください。

    1. 同一の親ディレクトリを持つ新しいディレクトリ libmenu cmd を作成します。

    2. ディレクトリ libmenu へ移動して、Sun WorkShop Visual を起動します。

    3. 図 9-1 に示すようなウィジェット階層を構築します。

 

    図 9-1 メニューバーウィジェット階層

明示的に名前が付けられたウィジェットだけがクラスのメンバーとして作成されま す。名前が付けられていないウィジェットは、それらを作成する関数に対して局所的になります。ウィジェ ットの命名により、そのクラスのメンバー関数から直接アクセスすることができるようになります。それら のウィジェットはデフォルトで限定公開メンバーであるため、任意の派生クラスのメンバー関数からもアク セスすることができます、

    4. 図 9-1 に示すようにウィジェットの変数名を設定します。

    5. カスケードボタンおよびプッシュボタンに対しての「ラベル」リソースをそれぞれ次の文字列に設定します 。
    File、Help、New、Exit

    6. シェルのリソースパネルを使用してシェルウィジェットをアプリケーションシェルとして指定し、シェルウ ィジェットのタイトルを「Demo」に指定します。

    これで階層の例が完成しました。では次に、メニューバーを C++ クラスとして指定します。

    7. ウィジェット階層内でメニューバーウィジェットを選択します。

    8. コアリソースパネルの「コード生成」のページを表示します。

    9. 図 9-2 に示すように、「構造」オプションメニューから「C++/Java クラス」を選択します。

 

    図 9-2 ウィジェットのクラスとしての指定

    10. 「適用」をクリックします。

Sun WorkShop Visual は、デフォルトで、ウィジェット名をデフォルトのクラス名およびインスタンス名として使用するため、 menubar と名前の付けられているウィジェットからは menubar_c という名前のクラスが作成されます。 menubar_c の基底クラスはウィジェットクラスに依存します。この場合は、 xd_XmMenuBar_c となります。後で説明しますが、これらの名前は変更することができます。

ウィジェットメンバーのアクセス制御

生成された menubar_c クラスは、クラスウィジェット ( menubar ) および名前が付いているすべての子孫ウィジェットをメンバーとして含みます。デフォルトでは、これらの ウィジェットは限定公開メンバーとなっていますが、コアリソースパネルを使用して任意のウィジェットの アクセス制御を変更することができます。以下の操作手順に従って、ヘルプメニューをクラスの公開メンバ ーにします。

    1. ウィジェット階層内で、「 help 」と名前が付けられているカスケードボタンを選択します。

    2. コアリソースパネルの「コード生成」ページを表示します。

図 9-3 に「コード生成」のページを示します。

 

    図 9-3 メンバーアクセス制御

    3. 「C++ アクセス」オプションメニューから「公開」を選択し、「適用」をクリックします。

C++ クラス・コード生成

クラスに対して生成されたコードは、生成された外部宣言ファイルにあるクラス宣 言と、C++ の基本コードファイルにある実装で構成されます。これらのファイルを生成するには、以下のように操作を 行います。

    1. 「コード生成」ダイアログを表示して、「言語」メニューで「C++」が選択されていることを確認します。< /P>

    2. 「コード」テキストフィールドに menubar.cpp と入力して、「生成」トグルをオンにします。

    3. 「外部宣言」テキストフィールドに menubar.h と入力して、「生成」トグルをオンにします。

    4. 「メインプログラム」テキストフィールドに menubar.cpp と入力して、「生成」トグルをオンにします。

    5. 「メークファイル」テキストフィールドに Makefile と入力して、「生成」トグルをオンにします。

    6. 「メークファイル」テキストフィールドの横にある「オプション」ボタンを押します。

    「メークファイル・オプション」ダイアログが表示されます。

    7. 「メークファイル・オプション」ダイアログで「新規メークファイル」と「メークファイル・テンプレート 」を両方オンにして、「了解」ボタンを押します。

    8. 「コード」テキストフィールドの横にある「オプション」ボタンを押します。

    図 9-4 に示す「C++コードのオプション」ダイアログが表示されます。

 

    図 9-4 「C ++コードのオプション」ダイアログ

    9. 図 9-4 で示すように「ヘッダーファイルをインクルード」テキストフィールドに menubar.h と入力して、「了解」ボタンを押します。

    10. 「コード生成」ダイアログの下の方にある「オプション」ボタンを押して、オプションを図 9-5 で示すように設定して、「了解」ボタンを押します。「文字列」リソースがコードに生成されるように設定 されていることを確認してください。

 

    図 9-5 menubar_c クラスの「コードオプション」ダイアログ

    11. 「コード生成」ダイアログの「生成」ボタンを押します。

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());
}

生成された C++ コードのコンパイル

コードの生成時に「メインプログラム」トグルを設定したため、 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 ディレクトリに移動します。

    2. $VISUROOT が、Sun WorkShop Visual のインストールのルートを指すように設定します。

    3. 次のように入力します。
    make

make が終了すると、libxdclass.a ライブラリが使用可能となります。

これで、生成されたメークファイルを使用してプログラムを構築する準備ができま した。

    注 - 生成されたメークファイルには $VISUROOT への参照が含まれているため、プログラムを構築する前に必ず環境変数 $VISUROOT を設定してください。

    4. 次のように入力して、メニューバーのプログラムを構築します。
    make

    5. 次のように入力して、アプリケーションを実行します。
    menubar

アプリケーションは、クラスがまったく存在しない場合と同様の外観および動作を 持ちます。

コールバック・メソッド

これまで、例としてウィジェット階層をクラスとして指定する方法と、生成される コードの形式を見てきました。現段階では、ウィジェット階層をクラスとしては活用していません。

コールバックおよびメンバー関数

Sun WorkShop Visual では、クラスメンバー関数をコールバック関数として指定することができる、単純なメカニズムを提供して います。これらのメカニズムをコールバック・メソッドと呼びます。使用する技術については、「コールバック・メソッド」で詳しく説明しています。

コールバック・メソッドの指定

コールバック・ダイアログを使用すると、イベントに対する応答で呼び出されるメ ンバー関数を指定することができます。特定のウィジェットに対してコールバック・メソッドを指定すると 、呼び出されるメソッドは、そのウィジェットの最も近くにあるクラス指定されたウィジェット (たいていはウィジェットそのもの) に属します。たとえば、メニューバー例にあるメニューボタン上のコールバック・メソッドは、 menubar_c クラスのメンバー関数を呼び出します。

以下の手順を使用して、 fm_new ボタンのクラスメソッドを宣言します。

    1. ウィジェット階層で fm_new ボタンを選択します。

    2. 「ウィジェット」メニューから「コールバック」を選択するか、ツールバーの「コールバック」ボタンを押 して、コールバックダイアログを表示します。

    3. 「コールバックのリスト」から「活性化 (activate)」を選択します。

    4. 「メソッドの名前」フィールドに次のように入力します。
    OnNew

    5. 「追加」をクリックします。

    これにより、図 9-6 に示すように、局所的メソッドのリストに OnNew が追加されます。

 

    図 9-6 コールバック・メソッドの指定

これは、メンバー関数 menubar_c::OnNew() をボタン fm_new の活性化コールバックを扱うメソッドとして指定します。この作業を行う際、ユーザーがまだ宣言を行なっ ていない場合には、Sun WorkShop Visual は親ウィジェットである menubar 上でもメソッドの宣言を行います。

同様に、 fm_exit ボタンにコールバック・メソッドを入力します。

    6. ウィジェット階層で fm_exit ボタンを選択します。

    7. 「コールバック」ダイアログで「活性化 (activate)」を選択します。

    8. 「メソッドの名前」フィールドに次のように入力します。
    OnExit

    9. 「追加」をクリックします。

    10. 「コールバック」ダイアログを閉じます。

クラスには menubar_c::OnNew() menubar_c::OnExit() という 2 つのコールバック・メソッドが存在することになります。

コールバック・メソッドに対してのコード生成

クラス内からコールバック・メソッドを使用すると、Sun WorkShop Visual は 2 つの別のメンバー関数に対し、ひとつに対しては完全な実装を、もうひとつに対してはスタブという宣言を 生成します。

    1. 「コード生成」ダイアログを表示して、「言語」オプションが「C++」に設定されていることを確認します 。

    2. 「スタブ」とラベルの付いたテキストボックスに menubarS.cpp と入力して、「生成」トグルをオンにします。

    3. 「メークファイル・オプション」ダイアログを表示します。

    4. 「新規メークファイル」トグルをオフに、「メークファイル・テンプレート」トグルをオンにして、「了解 」ボタンを押します。

    5. 「コード生成」ダイアログでメークファイルの「生成」トグルをオンにします。

    6. 「生成」ボタンを押します。

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() メソッドを実装します。

    1. fm_exit ボタンを選択します。

    2. 「コールバック」ダイアログを表示して、 OnExit() コールバックを選択します。

    3. 「コードを編集」ボタンを押します。

    <現作業ディレクトリ> /libmenu にある menubarS.cpp という名前のファイルが開きます。このファイルに記述された OnExit メソッドにコードを追加することができます。コールバックの編集についての詳細は、「Sun WorkShop Visual 内でのコールバックコードの編集」を参照してください。

    4. 以下のように、 menubar_c::OnExit() の実装を行います。

void 
menubar_c::OnExit (Widget w, XtPointer xt_call_data )
{
	XmAnyCallbackStruct *call_data = (XmAnyCallbackStruct*) 
		xt_call_data;
	exit(0);
}

    5. 「コールバック」ダイアログを閉じます。

    6. 次のように入力してメニューバーのプログラムを構築します。
    make

    7. 次のように入力してアプリケーションを実行します。
    menubar

    8. ファイルメニューから「閉じる」を選択します。

    プログラムが終了したことを確認してください。

メソッドの属性の編集

コールバック・メソッドには、アクセスレベルおよび純粋仮想か否かという 2 つの属性があります。アクセスレベルは、そのメソッドが派生クラスおよび外部コードからアクセスできる かどうかを決定します。また、メソッドは、基底クラスでの実装を持たないことを示す純粋仮想として指定 することができます。詳細は、第 8 章「構造化コード生成および再使用可能な定義」「C++ クラス」を参照してください。

属性はコールバックが最初に指定される時には、デフォルトに設定されています。 属性の初期設定は、クラスの祖先を持つ、またはクラスである任意のウィジェットで行うことができます。 しかし、その変更はクラスのルートウィジェット上で行われます。たとえば、クラス menubar_c OnNew() コールバック・メソッドは、 menubar ウィジェットそのものを使用してのみ編集することができます。

    1. ウィジェット階層で、メニューバーウィジェットを選択します。

    2. 「ウィジェット」メニューで「メソッド宣言」を選択し、「メソッド宣言」ダイアログを表示します。

    クラスに対して宣言されたコールバック・メソッドのリスト (特定のイベントに 対して呼び出されるメソッドのリストではない) が表示されます。このパネルを使用する と、コールバック・メソッドの編集、およびそのクラスのイベントによってではなく派生ク ラスにより呼び出される可能性のあるメソッドを宣言することができます。

    3. メソッド OnNew() を選択し、「純粋仮想」トグルを設定します。

    4. 「追加/更新」ボタンをクリックして変更を適用します。図 9-7 に示すような結果になります。

 

    図 9-7 コールバック・メソッドの編集

    5. コードを再度生成します。

純粋仮想メンバー関数に対する実装は、無効ではありませんが行う必要はありませ ん。

    6. スタブファイル menubarS.cpp temp.cpp にコピーします。

    7. スタブファイル menubarS.cpp を編集して OnNew() に対してのスタブ (例: 中括弧で囲まれたコード) を削除します。

    8. 前回と同じ手順でメニューバープログラムを構築します。

C++ コンパイラは、次のようなエラーメッセージを発します。

"menubar.cpp" 100 行目: 抽象クラス menubar_c に対して変数を作成することはできません。

menubar_c クラスが純粋仮想関数を含んでいるためインスタンス化することはできません。したがって、エラーが発生 することになります。この時点では、このクラスは基底クラスとしてのみ使用することができます。本章の 後半では、このクラスを派生クラスの基礎として使用します。

    9. temp.cpp menubarS.cpp にコピーして、 temp.cpp を削除します。

クラスメンバーの追加

この節および次の「派生クラスの作成」では、Sun WorkShop Visual の生成されたクラスにメンバーを追加する技術を説明します。ここで説明する技術は以下の 2 つです。

クラスメンバーをプレリュードとして追加

少数のメンバーを追加する最も簡単な方法としては、プレリュード機能を使用しま す。この機能を使用すると、Sun WorkShop Visual にコードの断片を入力することができ、また、それらを生成されたコードに渡すこともできます。

次の例では、コードを生成する前にコードプレリュードダイアログを使用してプレ リュードを追加します。

    1. ウィジェット階層でメニューバーウィジェットを選択します。

    2. ウィジェットメニューをプルダウンして、「コードプレリュード」を選択します。

    図 9-8 に示すダイアログが表示されます。

 

    図 9-8 クラスへの限定公開メンバーの追加

    3. コードプレリュードダイアログの「コードを直接編集」トグルをオフにします。

    プレリュードダイアログの右側に編集領域が表示されます。この編集領域にプレリ ュードを追加します。

    4. 「メソッド・プレリュード」とラベルのついたテキスト内にある「限定公開メソッド」トグルをオンにしま す (このトグルを表示するには、テキストをスクロールしなければならない場合もあります)。

    5. 右側のテキスト領域で Tab キーを押して次のように入力し、Return キーを押します。
    int modified;

    6. 「適用」をクリックし、次に「閉じる」をクリックします。

この操作の結果を確認するためには、以下のようにします。

    7. コードを再度生成します。

    8. コードファイル menubar.h 内で、クラス menubar_c にメンバーが追加されていることを確認します。

派生クラスの作成

コードプレリュード・ダイアログを使用すると、少数のコードを簡単に挿入するこ とができます。実質的な機能を追加するためには、多くの場合、生成されたクラスから派生する新しいクラ スを作成する方が良いでしょう。2 つのクラス間の論理的な違いを使用して、メンバーの追加および仮想関数の実装を行うことができます。

デフォルトでは、ルートウィジェットの変数名をもとに 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 参照)。

 

    図 9-9 インスタンスの名前の変更

    4. 「適用」をクリックして、「閉じる」をクリックします。

    5. コードを再度生成します。

元のクラスである menubar_c は、以前とまったく同様に宣言されています。しかし、Sun WorkShop Visual がクラスのインスタンスを作成するためにコードを生成する場合には、「インスタンス名」での名前が使用 されます。

menubar = new mymenubar_c;

派生クラスのコード作成

Sun WorkShop Visual は、 mymenubar_c クラスに対してコードを生成しません。ユーザーは、クラスおよび含まれるメソッドを実装するためのコー ドを宣言する、ヘッダーファイルを提供する必要があります。新しいクラスは、 menubar_c から派生しなければならないことを除いては、何ら制約を受けていません。この例の場合は、以下に示すコ ード例を使用します。

    1. 以下のコードを使用して、新しいファイルである mymenubar.h に、派生クラス mymenubar_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() 仮想コールバック・メソッドの実装を追加します。

    2. 以下のコードを使用して、新しいファイル mymenubar.cpp に、派生クラス mymenubar_c に対しての実装を作成します。

#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++ の「コード生成」ダイアログにある「ヘッダーファイルをインクルード」を使用して実行することができま す。

    3. 「コード生成」ダイアログを表示します。

    4. 「コード」ファイル名フィールドの横にある「オプション」ボタンを押します

    「コードオプション」ダイアログが表示されます。

    5. 「ヘッダーファイルをインクルード」フィールドに mymenubar.h と入力して「ヘッダーファイルをインクルード」トグルをオンにし、「了解」ボタンをクリックします。

図 9-10 に、新しいファイル名を表示した「コードオプション」ダイアログを示します。

 

    図 9-10 宣言ヘッダーの変更

    6. コードを生成します。

    7. メークファイルの中の行「 XD_ALL_C_SOURCES=... 」の前に以下の行を追加します。

XD_CC_SOURCES=mymenubar.cpp
XD_CC_OBJECTS=mymenubar.o 

    8. メークファイルの末尾に以下の行を追加します。

mymenubar.o:mymenubar.cpp
	$(CCC) $(CCFLAGS) $(CPPFLAGS) -c mymenubar.cpp

    注 - コンパイラの命令行のインデントは意図的なものです。

    9. メークファイルを保存します。

    10. 前回と同じ手順でメニューバープログラムを構築します。

この時点で、「ファイル」メニューの「新規」ボタンを押すと、アプリケーション はクラス 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 がインスタンスを含んでいるコードを生成する場合、ウィジェットを作成するための定義の作成関数が呼び 出されます。

前提条件

ウィジェットの階層は、以下の条件を満たす場合に定義にすることができます。

  • ルートウィジェットが変数名を持っている
  • ルートウィジェットが C++ クラスまたは C データ構造として指定されている
  • ルートウィジェットが別の定義の一部ではない
  • ウィジェット階層が定義を含んでいない
  • ウィジェット階層が大域的または静的ウィジェットを一切含んでいない

定義の指定

メニューバークラスを定義として指定するためには、以下のように操作します。

    1. 階層内でメニューバーウィジェットを選択します。

    2. ウィジェットメニューをプルダウンして、「定義」トグルを設定します。

    メニューバーウィジェットおよびその子孫が色付きの区画で囲まれ、定義を構成す ることを示します。

    3. デザインを menubar.xd として保存します。

    注 - 定義を含んでいるデザインは、パレットに追加する前に保存する必要があります。S un WorkShop Visual は、定義が使用されるごとに保存されたデザインファイルを使用します。単一のデザインファイル内には複 数の定義を持たせることができますが、各ファイルに定義をひとつだけ持たせておくと、追跡が簡単になり ます。

定義を作成すると、ウィジェットが定義内に凍結されます。凍結されたウィジェッ トのリソースパネルは使用できなくなるため、ウィジェットの追加またはウィジェット名の変更を行うこと はできません。定義を構成するウィジェットの変更は、一時的に定義を取り除くことによってのみ行うこと ができます。この作業は、定義を使用するデザインとの矛盾を発生させるおそれがあるので、十分な注意が 必要です。詳細は、第 8 章「構造化コード生成および再使用可能な定義」「定義の変更」を参照してください。

パレットへの定義の追加

この節では、新しい定義をウィジェットパレットに追加する方法を説明します。

    1. デザイン階層でメニューバーウィジェットを選択します。

    2. 「パレット」メニューから「定義を編集」を選択します。

    図 9-11 に示すダイアログが表示されます。

 

    図 9-11 パレットへの定義の追加

このダイアログを使用して、すでに定義マークが付けられているウィジェットを新 しい定義として追加、定義を削除、あるいは既存の定義を編集をすることができます。定義を追加するには 、以下の情報を入力する必要があります。

その他の属性については、第 8 章「構造化コード生成および再使用可能な定義」「定義のオンラインヘルプ」を参照してください。

作成時に設定されない属性は、後で設定することができます。たとえば、定義のテ ストおよびデバッグは、そのアイコンをデザインする前に実行できます。

    3. 「仮設定」ボタンを押します。

    「定義」、「ウィジェット名」、「保存ファイル」、および「インクルードファイ ル」フィールドにそれぞれの内容が設定されます。

メニューバーに指定した「インスタンス名」の名前は、定義が使用されるごとに適 用されます。

    4. 「アイコンファイル」フィールドに次のように入力します。
    menubar.xpm

アイコンは使用しなくても構いません。アイコンを指定しない場合は、ウィジェッ トパレットに追加される定義プッシュボタンのラベルとして、ルートウィジェットの名前が使用されます。 指定したアイコンファイルが存在しない場合は、定義のルートウィジェットの (Sun WorkShop Visual で使用している) アイコンファイルが、パレット上に表示されます。

Sun WorkShop Visual のピックスマップ・エディタを使用して、定義にするデザインのアイコンを作成することもできます。その 場合はウィジェット階層での選択を示すために使用される領域の色には「none」を使用します。ピックスマ ップエディタの詳細は 「ピックスマップ・エディタの使用」を、新しいウィジェットパレットの作成方法については 「パレットアイコン」を参照してください。

Sun WorkShop Visual リソースファイルを使用して、アイコンを指定することもできます。アイコンの指定を行うには、Sun WorkShop Visual リソースの名前を「アイコンリソース」フィールドに指定し、そのリソースを Sun WorkShop Visual リソースファイルにあるファイル名に設定します。

「定義を編集」ダイアログにあるその他のフィールドについては、本章で後述しま す。

    5. 「更新」をクリックします。

    指定したアイコンが Sun WorkShop Visual ウィジェットパレットに表示されます。子としてメニューバーを持つことができるウィジェットが選択され ると、そのアイコンは有効になります。

定義に対してのコードの生成

定義に対してのコードは、公開ヘッダーファイル (外部宣言ファイル) 内の宣言と、実装を含んでいるコードモジュールのふたつの部分で構成されます。インスタンスを含んでい るアプリケーションをコンパイルするために、コードモジュールが公開である必要はありません。ライブラ リにおいて、コンパイルされた形式で使用可能にすることができます。

定義に対してのコードだけ、つまりシェルまたは他のウィジェット、およびメイン プログラムを除いたコードだけを生成するには、以下の手順を使用します。

シェルウィジェットに対してコードが生成されないようにするためには、次のよう にします。

    1. 階層でシェルウィジェットを選択します。

    2. コアリソースパネルを表示して、「コード生成」ページを表示します。

    3. 「構造」オプションメニューを「子のみ生成」に設定して、「適用」 をクリックし、「閉じる」をクリックします。

この操作の後、Sun WorkShop Visual は C++ クラス、関数またはデータ構造体として指定されていないシェルおよびシェルの子を無視します。コードは メニューバーおよびその子孫にのみ生成されます。

また、メインプログラムの生成を以下のようにして抑制します。

    4. 「コード生成」ダイアログを開きます。

    5. 「メインプログラム」に対する「生成」トグルをオフにします。

    6. 「コード」、「スタブ」、および「外部宣言」に対する「生成」トグルがオンになっていて、外部宣言ファ イル名として menubar.h が指定されていることを確認します。

    7. 「メークファイル」に対する「生成」トグルをオフにします。

    8. 「生成」ボタン押します。

    9. デザインファイルを保存します。

これにより、定義および対応するクラスのコード作成に必要な処理が完了し、アプ リケーションで使用できるようになります。この実装を再使用するには、ライブラリとして使うことが一般 的です。

    10. 次のように入力して、ライブラリを生成します。

make menubar.o
make menubarS.o
make mymenubar.o
ar r libmenu.a *.o

インスタンスの作成

定義はパレット上のウィジェットと同様の方法で使用することができます。パレッ ト上のボタンをクリックすると、定義のインスタンスが作成されます。Sun WorkShop Visual は定義の階層をツリーにコピーします。ここで階層の修正および拡張を行うことができます。生成されたコ ードには、Sun WorkShop Visual がインスタンスを作成するための定義の作成関数の呼び出しを組み込みます。

menubar 定義を使用して新しいデザインを構築するには、以下のようにします。

    1. 「ファイル」メニューから「新規」を選択します。

    2. シェル、メインウィンドウ、新しい menubar 定義のウィジェットパレットアイコンをクリックします。

    新しい定義がウィジェットパレットに追加されて、手順 4 で指定したアイコンが作成されます。

    これにより、図 9-12 に示すウィジェット階層が作成されます。

 

    図 9-12 定義のインスタンスを含んでいる階層

インスタンスの構成要素は、単一の項目を形成することを示す色付きのボックスで 囲まれています。ルートウィジェットを除くすべてのウィジェットには、元の定義で持っていた名前と同じ 名前が指定されます。ルートウィジェットには、<ウィジェットクラス> <n> 形式のデフォルト名が割り当てられます。コードの信頼性を高めるためにも、明示的な名前を割り当てます 。

    3. インスタンスのルートウィジェット、 シェルおよびメインウィンドウ に、図 9-12 のように名前を付けます。

    4. シェルリソースパネルを使用して、シェルウィジェットをアプリケーションシェルに指定します。

インスタンスの修正および拡張

インスタンスを作成した後、生成されたコード内で変更を実行できる場合に限り、 インスタンスを変更することができます。たとえば、ウィジェットが公開アクセスを持っている場合はその ウィジェットへのリソースの設定、あるいは子の追加を行うことができます。ウィジェットの削除、名前の 変更はできません。しかし、ルートウィジェットは例外となります。インスタンスのルートウィジェットは メンバー関数 xd_rootwidget() を使用して呼び出すことができるため、常に修正することができます。

この例では、定義のすべての構成要素は help ボタンを除いて限定公開となっています。これは、 help ボタンのラベルのみが変更可能であることを意味します。同様に、 help ボタンの下に別のウィジェットを追加することができますが、 filemenu メニューには追加することはできません。

    1. ウィジェット階層内で help ウィジェットを選択します。

    2. ウィジェットパレットでメニューアイコンをクリックし、プッシュボタンアイコンをクリックします。

    help カスケードボタンの下に選択項目を 1 つだけ持つメニューが追加されます。

    3. ウィジェット名を図 9-13 に示すように設定します。

 

    図 9-13 定義のインスタンスの拡張

    4. hm_about ボタンのラベルを「About...」に設定します。

現在、ユーザーは定義内の他のウィジェットを修正することはできません。たとえ ば、 filemenu にボタンを追加することはできません。しかし、定義からのサブクラスを作成すると、公開ウィジェットに 加えて限定公開ウィジェットも修正することができます。その方法は、次の「派生クラスの作成」で説明し ます。

派生クラスの作成

定義に対応しているクラスのほとんどのメンバーは限定公開であるため、定義のイ ンスタンスでそれらを呼び出すことはできません。これを解決するためには、次の 2 通りの方法があります。

2 番目の方法は、カプセル化された構造をよりよく維持することができます。また、コールバック・メソッド を活用することもできます。

    1. ウィジェット階層内でメニューバーウィジェットである appmenu を選択します。

    2. コアリソースパネルの「コード生成」ページを表示します。

    3. 「構造」オプションメニューから「C++ クラス」を選択して「適用」をクリックし、リソースパネルを閉じます。

    menubar ウィジェットは図 9-14 に示されるように、クラスとして指定されます。このクラスは定義に対応するクラスから派生されます。

 

    図 9-14 定義からの派生クラスの作成

クラスのメンバー関数は、 mymenubar_c の限定公開メンバーを呼び出すことができるため階層内の任意の場所にウィジェットを追加することができ ます。

    4. ウィジェット階層内で filemenu ウィジェットを選択します。

    5. メニューに 2 個のプッシュボタンを追加し、「Open...」および「Save...」というラベルを付けます。

    6. 新しいボタンの変数名を fm_open および fm_save に設定します。

    7. マウスボタン 1 を使用して、新しいボタンを図 9-15 に示す位置までドラッグします。

 

    図 9-15 派生クラスの拡張

定義の順序は変更できません。新しいウィジェットを定義に追加することはできま すが、すでに定義内の一部であるウィジェットを移動することはできません。

    8. 階層内で fm_open を 選択します。

    9. 「ウィジェット」メニューから「コールバック」を選択するか、ツールバーの「コールバック」ボタンを選 択して、コールバックダイアログを表示します。

    10. コールバックリストから「活性化 (activate)」を選択します。

    11. 「メソッドの名前」フィールドに次のように指定します。
    OnOpen

    12. 「追加」をクリックします。

    13. 上述の手順を繰り返し、 fm_save に対しての「活性化 (activate)」コールバック・メソッドを OnSave に設定します。

    14. 「コールバック」ダイアログを閉じます。

この方法は C 構造体に対しても有効です。Sun WorkShop Visual は定義の構造体の拡張である新しい構造体を生成します。

コールバック・メソッドの書き換え

メニューバーに対応するクラス appmenu_c は、継承される OnNew() OnExit() 、および appmenu_c 自体により定義される OnOpen() OnSave() という 4 種類のコールバック・メソッドを持っています。しかし、継承されるメソッドは書き換えることができるた め、派生クラスに基底クラスとは異なる動作を持たせることができます。

 

    図 9-16 「メソッド宣言」ダイアログ

OnExit() OnNew() menubar_c から継承されるのに対し、 OnSave() OnOpen() appmenu_c に局所的です。継承されたメソッドは角括弧 [ ] で囲まれて表示されます。

    3. テキストフィールドに、次のように入力します。
    OnExit

    4. 「純粋仮想」トグルがオフになっていることを確認して、「追加/更新」を押します。

    OnExit() が局所的メソッドのリストに追加されます。この時点で書き換えを行うことができます。

書き換えられたメソッドの実装

書き換えられたメソッドを実装するには、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 のとおりに設定します。

     

    図 9-17 アプリケーションのコード生成

    12. 「了解」ボタンを押します。

    13. 「生成」ボタンを押し、「コード生成」ダイアログを閉じます。

    14. スタブファイル appS.cpp を以下のように完成させます。

...
#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 フラグを更新するだけのダミーの関数です。

アプリケーションのメニューバーの機能は、現段階では以下のようになっています 。

  • クラスのコンストラクタにおいて、 modified フラグは TRUE に初期設定されます。「Open...」により TRUE に、また「New」および「Save...」により FALSE に設定されます。
  • 修正されたフラグが設定されていない場合は、「Exit」はアプリケーションを終了 します。フラグが設定されている場合はベルを鳴らします。
  • 「Open...」および「Save...」は、標準出力で情報メッセージを作成します。
  • 15. メークファイルの中の「 MOTIFLIBS= 」で始まる行と「 CFLAGS= 」で始まる行を以下のように変更します。

MOTIFLIB=-lmenu -lXpm -lXm -lXt -lX11
CFLAGS=-I. ${XINCLUDES} -I${XPMDIR} -I../libmenu \
-L../libmenu

    16. メークファイルを保存します。

    17. 次にように入力して、プログラムを構築します。
    make

    18. アプリケーションを実行し、メニューが意図したとおりに動作することを確認します。

    19. アプリケーションをディレクトリ cmd app.xd として保存します。

定義とリソースファイル

定義の構成要素であるウィジェットのリソース値は、明示的に設定することも、リ ソースファイルに指定することもできます。定義のリソースファイルを指定するとそのファイルは、その定 義のインスタンスを含んでいるすべてのデザインのリソースファイルにインクルードされます。

ここまでの例では、すべてのリソースは明示的に設定されていました。以下の手順 を使用して、リソースファイル中の文字列リソースを使用するようにメニューバー定義を再生成してみまし ょう。

    1. libmenu ディレクトリのデザインファイル menubar.xd を開きます。

    2. 「コード生成」ダイアログを表示して、「言語」メニューが「C++」に、「ディレクトリ」が libmenu ディレクトリに設定されていることを確認します。

    3. 「コード生成」ダイアログから「コードオプション」ダイアログを表示して、「文字列」オプションメニュ ーを「リソースファイル」に設定し、「了解」ボタンを押します。

    これにより、ボタン上のラベルなどの明示的に記述された文字列リソースが取り除 かれます。

ここで、文字列リソースを含んでいるリソースファイルを生成します。

    4. 「コード生成」ダイアログで、「 X リソース」テキストボックスに menubar.res と入力して、横にある「生成」トグルをオンにします。

    5. 「コード」テキストボックスの横にある「生成」トグルがオンに、「メインプログラム」および「メークフ ァイル」の横にある「生成」トグルがオフになっていることを確認します。

    6. 「生成」ボタンを押します。

    7. デザインを保存します。

    8. libmenu ディレクトリで、次にように入力します。
    make clean

    古いオブジェクトファイルが削除されます。

    9. 手順 10 と同じ手順でライブラリを再度構築します。

定義の編集

前節では、文字列リソースがリソースファイルに保存されるように、定義の生成さ れたコードを変更しました。次に、 menubar 定義を編集してリソースファイルを指定します。

    1. パレットメニューから「定義を編集」を選択します。

    2. 「定義を編集」ダイアログで、定義リストから menubar を選択します。

    3. 「リソースファイル」フィールドに、次の行を入力します。

	../libmenu/menubar.res

    4. 「更新」をクリックします。

    定義への変更がユーザーの定義ファイル ( $HOME/.xddefinitionsrc ) に保存されます。

    注 - 「定義を編集」ダイアログを使用すると、随時リソースファイルの指定を行うこと ができます。この手順を実行するために、元の menubar.xd デザインを読み込む必要はありません。

インスタンスと定義リソースファイル

定義に対してリソースファイルを指定すると、Sun WorkShop Visual は定義のインスタンスを含むすべてのデザインにそのファイルをインクルードします。リソースファイルを 読み取る Xlib メカニズムは、指示文を解釈し、定義に対するリソースファイルの検索に使用します。以下の手順を使用し て、この動作を app.xd アプリケーションで試してみます。

    1. cmd ディレクトリのデザインファイル app.xd を開きます。

    2. 「コード生成」ダイアログを表示して、「言語」メニューが「C++」に設定されていることを確認します。< /P>

    3. 「 X リソース」テキストボックスに app.res と入力して、横にある「生成」トグルをオンにします。

    4. 「コード」および「メインプログラム」テキストボックスの横にある「生成」トグルを、両方オンにします 。

    5. 「スタブ」、「外部宣言」、および「メークファイル」の横にある「生成」トグルがすべてオフになってい ることを確認します。

    6. 「コード生成」ダイアログから「コードオプション」ダイアログを表示して、「文字列」オプションメニュ ーを「リソースファイル」に設定し、「了解」ボタンを押します。

    7. 「生成」ボタンを押します。

アプリケーションに対する X リソースファイルには、以下の指令が含まれています。

! Generated by Sun WorkShop Visual 
#include "../libmenu/menubar.res"

Xlib は、この #include 指令を、アプリケーションリソースファイルを含んでいるディレクトリへの相対的なパス名の指定として解 釈します。詳細は、Xlib の資料を参照してください。

    8. 次のように入力して、プログラムを構築します。
    make

    9. 環境変数 XENVIRONMENT をリソースファイル名に設定します。

    設定するための構文は、使用するシェルの種類によって異なります。以下の例を参 考にしてください。C シェルの場合は、次のように入力します。

setenv XENVIRONMENT app.res 

Bourne シェルの場合は、次のように入力します。

XENVIRONMENT=app.res; export XENVIRONMENT 

    注 - この他にも、X に X リソースファイルを認識させる方法があります。詳細は、X ウィンドウシステムに関する資料を参照してください。参考資料については、付録 E 「参考資料」をご覧ください。

    10. アプリケーションを実行し、メニューが意図したとおりに動作することを確認します。

    11. デザインを保存して、Sun WorkShop Visual を終了します。

 


前へ 次へ 目次 文書セット ホーム

サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.