GEOS-SC は、GeosSC.exe という単一のプログラムです。このプログラムは、「モジュール」と呼ばれる複数のコードで構成されています。モジュールは、アプリケーション、ライブラリ、またはドライバのいずれかです。ここでは、新しいアプリケーション モジュールの作り方を説明します。
以下の例では、ボタンを使って画面に「こんにちは みなさん!」と表示するアプリケーションを作成します。アプリケーションが担当する機能と、単純なユーザー
インターフェイスを作成する方法について説明します。
このチュートリアルの各ステップには、 (ヘッダー | ソース | リソース) というリンクがあります。 これらは、アプリケーションのヘッダー ファイル (.h ファイル)、メイン ソース コード ファイル (.cpp ファイル)、およびリソース ファイル (.str ファイル) にそれぞれリンクされています。リソース ファイルには、ユーザーに表示する文字列が格納されます。これについては後で説明します。
サンプル アプリケーションを作成するには、次の手順に従います。
GEOS-SC のワークスペースをまだ開いていない場合は、[スタート] メニューで [GEOS_SC SDK] メニューの [GEOS-SC workspace] をクリックしてワークスペースを開きます。Microsoft Visual C++ からワークスペースを開くには、[ファイル] メニューの [ワークスペースを開く] をクリックし、[GeosSC.dsw] を選択してください。
アプリケーションを新しく作成するには、
C:\geos-sc\appl\>mkdir mystuff C:\geos-sc\appl\>mkdir mystuff\tutsamp |
まず、C++ ソース ファイルである tutsamp.cpp を作成します。 [ファイル] メニューから [新規作成] を選択します。
ダイアログ ボックスで [C++ ソース ファイル] を選択して [ファイル名] に tutsamp.cpp と入力します。次に、tutsamp ディレクトリへのパス (この例では、C:\GEOS-SC\appl\mystuff\tutsamp) を [位置] に指定します。[OK] をクリックします。
これらの手順を繰り返して、tutsamp.h および tutsamp.str を作成します。ただし、これらのファイルの場合は、[C++ ソース ファイル] ではなく、[C/C++ ヘッダー ファイル] を選択します。 完了すると、これらのファイルがステップ 4 で示されているように、[Geos-SC ファイル] の下に表示されます。
C:\geos-sc\appl\mystuff\tutsamp>mkjam Jamfile created. No toolchain specified, using "Microsoft32" No configuration specified, using "ErrorCheck" Using NT.jam Using Microsoft32.jam Using (optional) GeosSc.jam ...found 12 target(s)... ...updating 2 target(s)... MakeDspFile ..\..\..\appl\mystuff\tutsamp\tutsamp.dsp ...updated 2 target(s)... C:\geos-sc\appl\mystuff\tutsamp> |
... Module appl samples shell envshell ; Module appl samples internet netman ; Module appl browser ; Module appl mystuff tutsamp ; Module appl javalaunch : Inactive ; ... |
ユーザーに表示する文字列を tutsamp.str ファイルに記述します。 (リソース | ヘッダー | ソース)
tutsamp.str ファイルを開くには、[ワークスペース] ビューの [FileView] タブで tutsamp.str のエントリ ([GeosSC ファイル] の下に表示される) をダブルクリックします。
このファイルの内容を、前の (リソース)
リンクで表示される内容で置き換えます。
.prefix TUTSAMPAPP FRAME_TITLE "サンプル" BUTTON_LABEL "ここをクリック" LABEL_TEXT "こんにちは みなさん!" |
アプリケーションでこれらの文字列を使うには、C++ コードで次のことを行う必要があります。
システムに対してアプリケーションを表すコードを tutsamp.h ファイルに記述します。 (リソース | ヘッダー | ソース)
[FileView] タブで、tutsamp.h ファイルを開きます。このファイルの内容を、前の (ヘッダー) リンクで表示される内容で置き換えます。
tutsamp.h の前半を調べてみましょう。
#ifndef _TUTSAMPAPP_H_ #define _TUTSAMPAPP_H_ #include <toolkit/uifact.h> //UI オブジェクト (FlexFrame など) を使用します #include <ui/appbase.h> //AppBase クラスを使用します #include <toolkit/lisact.h> //ActionListenerInterface クラスを使用します #include <resapp/resapp.h> //ResidentApplication クラスを使用します class TutorialApp : public ActionListenerInterface, public AppBase { public: TutorialApp(void); // UI を構築するために、SetAppContext をオーバーライドします virtual void SetAppContext(const TCHAR *context); // アプリケーションの状態を保存するために、GetAppContext をオーバーライドします virtual TCHAR *GetAppContext(void); // ボタンの押下に対応するために、ActionPerformed をオーバーライドします virtual void ActionPerformed(ActionEvent& event); // アプリケーション終了時のクリーンアップを行うために、Exit をオーバーライドします virtual void Exit(void); private: // UI を作成するヘルパー関数です Result BuildUI(void); // UI が既に構築されているかどうかを示すフラグです Boolean _builtUI; // このオブジェクトは "こんにちは みなさん!" という文字列を表示します。 // コードからラベルの表示と非表示を切り替えるときに便利なように、 // ポインタを宣言します FlexLabel *_helloworldLabel; // アプリケーションの UI を終了するとき // 削除するのに便利なように、 // ポインタを宣言します VerticalFlowLayout *_layout; }; |
アプリケーション ベース オブジェクトは、アプリケーションの周辺的な機能を定義する場所としても便利です。このアプリケーションの場合、機能と呼べるものはほとんどありません。ボタンの押下に反応するだけです。ここでは、ActionListenerInterface
を継承し、ActionPerformed()
をオーバーライドすることにより、ボタンの押下に対応します。このオブジェクトがボタンの押下を「受信」できるようにする方法については、後で説明します。
tutsamp.h ファイルで常駐アプリケーションを定義します。(リソース | ヘッダー | ソース)
tutsamp.h の残りのコードを調べてみましょう。
// ユーザーに表示されない文字列です const TCHAR *const TUTSAMP_APP_NAME = _TEXT("tutsamp"); // システムにアプリケーションを登録する ResidentApplication のサブクラスです class TutorialSampResidentApplication : public ResidentApplication { public: TutorialSampResidentApplication() : ResidentApplication(TUTSAMP_APP_NAME) {}; virtual AppBase *CreateAppBase(void) { return new TutorialApp; } }; static TutorialSampResidentApplication tutsampApp; #endif // _TUTSAMPAPP_H_ |
_TEXT() マクロは、文字列定数の定義に使います。_TEXT()
を使うと、TCHAR と同様に、さまざまな文字セットに対応することができます。_TEXT()
は TCHAR 文字列を返します。
アプリケーションのソース コードの本体を tutsamp.cpp ファイルに記述します。(リソース | ヘッダー | ソース)
[FileView] タブを使って tutsamp.cpp ファイルを開きます。このファイルの内容を、前の (ソース) リンクで表示される内容で置き換えます。
このコードの先頭部分を調べてみましょう。
#include <system.h> //GEOS-SC の標準データ型を使用します #include <toolkit/uifact.h> //UI ファクトリを使用します #include <flexui/javaspui.h> //UI のヒントを使用します #include <tstring.h> //TCHAR 文字列関数 (Tstrcpy) を使用します #include "tutsamp.h" //クラス定義を使用します #include "resource.h" //ユーザーに表示される文字列を使用します // アプリケーションの static 変数に対してシステムが使用する名前を設定します AppNameAttribute tutsampAppName(&tutsampApp, TUTSAMPAPP_FRAME_TITLE); TutorialApp::TutorialApp() : _builtUI( FALSE ), _layout( NULL ) {}; |
起動と終了を処理するコードを tutsamp.cpp ファイルに記述します。 (リソース | ヘッダー | ソース)
ソース ファイルの次の部分を調べてみましょう。
// アプリケーションの状態を更新します。必要な場合は UI を構築します /* virtual */ void TutorialApp::SetAppContext(const TCHAR *context) { // アプリケーションの UI がまだ構築されていない場合は構築します if ((!_builtUI) && BuildUI() != SUCCESS) { EC_WARN("UI を作成できません。"); Exit(); } // コンテキスト文字列があれば、解析して UI を更新します if (context) { if (Tstrcmp( context, _TEXT("+")) == 0) { _helloworldLabel->SetVisible(TRUE); return; } if (Tstrcmp( context, _TEXT("-")) == 0) { _helloworldLabel->SetVisible(FALSE); return; } EC_WARN("解釈できないコンテキスト文字列です。"); } } // End of TutorialApp::SetAppContext() // アプリケーションの状態を文字列にエンコードします /* virtual */ TCHAR * TutorialApp::GetAppContext(void) { if (_builtUI != TRUE ) { return NULL; } TCHAR scratch[30]; if (_helloworldLabel->IsVisible() == TRUE) { Tstrcpy( scratch, _TEXT("+")); } else { Tstrcpy( scratch, _TEXT("-")); } TCHAR *context = new TCHAR[Tstrlen( scratch ) + 1 ]; if ( context == NULL ) { EC_WARN("コンテキスト文字列を割り当てられませんでした; コンテキストは保存されません。"); return NULL; } Tstrcpy( context, scratch ); return context; } // End of TutorialApp::GetAppContext // アプリケーションの終了時にクリーンアップを行います /* virtual */ void TutorialApp::Exit(void) { delete _layout; // 継承したメンバ関数を呼び出してデフォルトの動作を行います AppBase::Exit(); } // End of TutorialApp::Exit() |
tutsamp.cpp ファイルでユーザー インターフェイス オブジェクトをセットアップするユーティリティ関数 BuildUI() を定義します。 (リソース | ヘッダー | ソース)
この例の関数 SetAppContext()では、ユーティリティ関数
BuildUI() を使ってアプリケーションのユーザー インターフェイスを作成します。ここでは、この関数の本体を定義します。この関数は、アプリケーションのユーザー
インターフェイスを構成するオブジェクトを作成します。最初に作成されるのはフレームです。フレームは画面
(ウィンドウ) であり、ほかのオブジェクトを追加することができます。BuildUI()
によるフレーム オブジェクトのセットアップを調べてみましょう。
Result TutorialApp::BuildUI(void) { FlexFrame *frame = theUIFactory->CreateFlexFrame( HINT_FRAME_WITH_NO_CLOSE_BUTTON, TUTSAMPAPP_FRAME_TITLE ); if (frame == NULL) { EC_WARN("フレームを作成できませんでした。"); return FAILURE; } if (Add(frame) != SUCCESS) { EC_WARN("フレームを AppBase に追加できません。"); delete frame; return FAILURE; } ... |
文字列 TUTSAMPAPP_FRAME_TITLE は、.str ファイルで定義したものです。
メモリの割り当てが失敗していないか、常に調べるようにしてください。ここでは、フレームの作成に成功したかどうかを確認します。成功しなかった場合は、UI の作成を中止し、FAILURE を返します。また、EC_WARN() マクロを使って問題を報告します。EC_WARN() は "printf() デバッグ" に相当し、DOS シェルにメッセージを出力します。EC (エラー チェック) コードの利点と詳細については、「Coding Conventions: Error Checking Code」を参照してください。sys_info ライブラリの API リファレンスには、EC マクロの一覧があります。
フレームの作成に成功したら、アプリケーション ベース オブジェクトの「 UI ツリー」に追加します。このツリーは、UI オブジェクトを階層化し、オブジェクト間の親子関係を管理するものです。ある UI オブジェクトが別の UI オブジェクトに含まれている場合は、前者を「子」、後者を「親」と呼びます。たとえば、あるボタンがダイアログ ボックス内に表示される場合、このボタンはダイアログ ボックスの子オブジェクトと呼ばれます。ほかのオブジェクトを含むことができるのは、FlexContainer から派生したオブジェクトのみです。ある UI オブジェクトを別の UI オブジェクトの子オブジェクトにするには、親オブジェクトのメンバ関数 Add()を使います。OS の関数で失敗する可能性のあるものについては、必ず戻り値を調べるようにしてください。ここでは、アプリケーション ベース オブジェクトの Add() の戻り値を調べ、フレームの追加が成功したかどうかを確認しています。
アプリケーション ベース オブジェクトへのフレームの追加で問題が発生した場合は、delete
を使ってフレームを削除します。フレームは削除しますが、アプリケーション
ベース オブジェクトは削除しません。このオブジェクトはアプリケーション終了時に自動的に削除され、UI
ツリーのオブジェクトもすべて削除されます。フレームは UI ツリーに追加されないため、削除する必要があります。
tutsamp.cpp ファイルで BuildUI() を完成します。 (リソース | ヘッダー | ソース)
関数 BuildUI() の定義の残りの部分を調べてみましょう。
... _layout = new VerticalFlowLayout; if ( _layout == NULL ) { EC_WARN("フレームのレイアウトを割り当てられませんでした。"); return FAILURE; } frame->SetLayout(_layout); FlexButton *button = theUIFactory->CreateFlexButton( HINT_BUTTON_JAVA_LOOK_AND_FEEL); if (button == NULL) { EC_WARN("ボタンを作成できませんでした。"); return FAILURE; } if ( frame->Add(button) != SUCCESS ) { EC_WARN("ボタンをフレームに追加できませんでした。"); delete button; return FAILURE; } button->SetLabelString(TUTSAMPAPP_BUTTON_LABEL); if ( button->AddActionListener(*this) != SUCCESS ) { EC_WARN("ボタンにアクション リスナーを追加できませんでした。"); return FAILURE; } _helloworldLabel = theUIFactory->CreateFlexLabel(); if ( _helloworldLabel == NULL ) { EC_WARN("ラベルを作成できませんでした。"); return FAILURE; } if ( frame->Add(_helloworldLabel) != SUCCESS ) { EC_WARN("ラベルをフレームに追加できませんでした。"); delete _helloworldLabel; return FAILURE; } _helloworldLabel->SetText(TUTSAMPAPP_LABEL_TEXT); _helloworldLabel->SetVisible( FALSE ); frame->SetVisible(TRUE); _builtUI = TRUE; return SUCCESS; } // End of TutorialApp::BuildUI() |
tutsamp.cpp ファイルでボタンの押下を処理するメンバ関数 ActionPerformed()
を定義します。 (リソース | ヘッダー
| ソース)
/* virtual */ void TutorialApp::ActionPerformed(ActionEvent& event) { USE_IT( event ); if (_helloworldLabel->IsVisible()) { _helloworldLabel->SetVisible(FALSE); } else { _helloworldLabel->SetVisible(TRUE); } } // End of TutorialApp::ActionPerformed() |
[アウトプット] ウィンドウの [ビルド] タブに「jam の実行エラー」というメッセージが表示された場合は、コンパイルかリンクでエラーが発生しています。エラーや警告の通知を確認してください。
GEOS-SC エミュレータのディスプレイ ウィンドウにほかのアプリケーションが表示された場合は、作成したアプリケーションを前面に移動する必要があります。ディスプレイ ウィンドウにほかのアプリケーションが表示されている場合は、ディスプレイ ウィンドウをアクティブにし、F1 キーを押します。次に、表示されたダイアログ ボックスで [サンプル] を選択し、[Switch To] をクリックします。
[ここをクリック] をクリックして "こんにちは みなさん!" ラベルを表示します。
プログラムによる状態の保存を見るには、次の手順に従います。
ダイアログ ボックスが表示されます。
ダイアログ ボックスの背後でアプリケーションが閉じます。これでアプリケーションは終了しました。
ダイアログ ボックスの背後でアプリケーションが再び表示されます。これでアプリケーションは起動し、状態を復元しました。