GEOS-SC : Flex UI : Flex UI 使用法 : 複数の UI の統合

このドキュメントについて | 用語集 | アプリケーションの記述方法 | ユーザー インタラクションの検出方法 | 複数の UI の統合


ほとんどのアプリケーションは 2 種類以上の Flex UI コンポーネントから構成されます。アプリケーションが複雑になると、複数の EventListener を使用してユーザーの操作をモニターします。したがって各オブジェクトの EventHandler は、共用されたり、互いに依存することがあります。

前のセクションのアドレス帳の例は FlexTableFlexListFlexButton と、対応する EventHandler TableSelectionChangedItemStateChangedActionPerformed で構成されていました。

このアプリケーションのデザインでは 、 EventHandler が他の EventHandler を呼び出す場合があります。例えば、ユーザーがアドレス帳のエントリの名前を変更したときは TableSelectionChanged が呼び出されます。ユーザーのインタラクションによっては TableSelectionChangedItemStateChanged を呼び出してリストを更新します。

ここでは次に示す Flex UI コンポーネントを使ってメモ帳アプリケーションを作成し、複数ファイルへの保存やファイル操作用のメニューを実装します。

複数のファイルにデータを保存し、ユーザーがメニューからファイル操作を選択できるメモ帳アプリケーションの作成手順を、次に示します。

  1. ヘッダー ファイルでクラス Notepad2App を宣言します。
  2. アプリケーションを登録してユーザー インターフェイスを作成します。
  3. アプリケーションのフレームをシステムにアタッチします。
  4. ファイル操作用の FlexMenu をフレームにアタッチします。
  5. ヘルパー関数 CreateDialogUI を呼び出してダイアログをアタッチします。
  6. FlexTextArea をフレームにアタッチし、ユーザー インターフェイスを表示します。
  7. ヘルパー関数 CreateDialogUI を追加してアプリケーションのダイアログを生成します。
  8. EventHandler MenuItemChosen を追加してメニュー イベントを処理します。
  9. EventHandler ItemStateChanged を追加してリスト イベントを処理します。
  10. ファイルの保存用と読み込み用のコードを ItemStateChanged に追加します。
  11. アプリケーションをコンパイルして実行します。


ヘッダー ファイル notepad2.h で、クラス Notepad2App を宣言します。 (リソース | ヘッダー | ソース)

#ifndef _NOTEPAD2_H_
#define _NOTEPAD2_H_

#include <ui/appbase.h>
#include <toolkit/lisact.h>          
#include <toolkit/adptext.h>
#include <toolkit/lisitem.h>

class Notepad2App : public ItemListenerInterface, public MenuAdapter, public AppBase {
public:

    // アプリケーションの初期画面の UI を作成するために、SetAppContext を
    // オーバーライドします
    void SetAppContext(const TCHAR *context);
    
    // 初期画面用の UI を作成するためのヘルパー関数
    Result AttachNotepad2AppUI(void);
    Result CreateDialogUI(static const TCHAR *title, FlexDialog **dialog );
    
    // MenuItemChosen はメニューの MenuEvents を処理します
    void MenuItemChosen(MenuEvent& event);

    // ItemStateChanged はリストの ItemEvents を処理します
    void ItemStateChanged(ItemEvent& event );

    // アプリケーションを終了する為の Exit をオーバーライドします
    virtual void Exit(void);

    // グローバルなコンポーネント    
    FlexTextArea   *_textDisplay;
    FlexDialog     *_saveDialog;
    FlexDialog     *_openDialog;
    
    // Open ダイアログ ボックスの id を保持します
    int _dialogOpen;
};      

// メニュー アイテム id を列挙します
const FlexComponentID NEW_MENU_ITEM = 0;
const FlexComponentID SAVE_MENU_ITEM = 1;
const FlexComponentID OPEN_MENU_ITEM = 2;

#endif /* _NOTEPAD2_H_ */

ソース ファイル notepad2.cpp で、アプリケーションを登録してユーザー インターフェイスを作成します。 (リソース | ヘッダー | ソース)


#include <kernel/geode.h>
#include <kernel/system.h>
#include <flexui/demoui.h>
#include <toolkit/uifact.h>
#include <toolkit/lmdialog.h>
#include <toolkit/lmflow.h> 
#include <pos/fsmgr.h>
#include <pos/file.h>
#include <resapp/resapp.h>
#include <locale/locale.h>
#include "resource.h"
#include "notepad2.h"

// アプリケーションのメニュー用文字列定数を作成します
static const TCHAR *MENU_ITEMS[3]       = {_TEXT("New"), _TEXT("Save"), _TEXT("Open")};

// テキストを保持するバッファを作成します
TCHAR	*_notepad2TextString;

// アプリケーションを登録します
class Notepad2ResidentApplication : public ResidentApplication {
 public:
    Notepad2ResidentApplication() : ResidentApplication(_TEXT("notepad2")) {};
    virtual AppBase *CreateAppBase(void) {return new Notepad2App;}
};

static Notepad2ResidentApplication notepadApp2;
static AppNameAttribute notepadApp2Name(¬epadApp2, NOTEPAD2_APP_TEXT);


// アプリケーションを作成します
void
Notepad2App::SetAppContext(const TCHAR *)
{
    _dialogOpen = 0;

    if (AttachNotepad2AppUI() == FAILURE) { 
        EC_WARN("Unable to build Notepad2 application."); 
    }

    // テキスト バッファの領域を割り当てます
    _notepad2TextString = new TCHAR[600];
}

フラグ _dialogOpen には開いているダイアログに対応した値が入るので、現在開いているダイアログがないことを示すために SetAppContext 内で値をリセットします。


メソッド AttachNotepad2AppUI で、アプリケーションにフレームをアタッチします。 (リソース | ヘッダー | ソース)


Result
Notepad2App::AttachNotepad2AppUI(void)
{
    FlexFrame	    *frame;
    FlexMenu        *menu;
    FlexMenuButton *menuButton;
 
    // アプリケーションのメインのフレームを作成します
    frame = 
        theUIFactory->CreateFlexFrame(HINT_FRAME_WITH_NO_CLOSE_BUTTON, NOTEPAD2_APP_TEXT);
    if (frame == NULL) { return FAILURE; }
    
    // フレームのレイアウトを作成します
    VerticalFlowLayout *mainFrameLayout = 
        new VerticalFlowLayout(	10, 
                                VerticalFlowLayout::Y_JUSTIFY_CENTER, 
                                LayoutManagerInterface::X_ALIGN_LEFT);
    if (mainFrameLayout == NULL) { return FAILURE; }

    // フレームにレイアウトを加え、フレームをアプリケーションに加えます
    frame->SetLayout(mainFrameLayout);
    this->Add(frame);

メソッド AttachNotepadApp2UI で、FlexMenu をフレームにアタッチしてファイル操作を処理します。 (リソース | ヘッダー | ソース)

    
    menu = theUIFactory->CreateFlexMenu(HINT_PULL_DOWN_MENU, NOTEPAD2_FILE_MENU_TEXT);
    if (menu == NULL) { return FAILURE; }
    
    for ( int i = 0; i < 3; i++) {
        menuButton = theUIFactory->CreateFlexMenuButton( 0,
                                                            MENU_ITEMS[i], 
                                                            (MenuItemID) i);
        if (menuButton == NULL) { return FAILURE; }
        else { menu->Add(menuButton); }
    }
    
    menu->AddMenuListener(*this);
    
    frame->Add(menu);

メソッド CreateFlexMenuButton を呼び出して、各 FlexMenuButton を作成します。 メニュー ボタンの作成に成功すれば、それをメニューに追加します。

メニューを作成した後に、AddMenuListener メソッドを使用してメニューの選択を処理する EventHandler を追加し、それからメニューをフレームに追加します。


AttachNotepadApp2UI で、ヘルパー関数 CreateDialogUI を呼び出してダイアログを作成します。 (リソース | ヘッダー | ソース)

    
    if ( CreateDialogUI(NOTEPAD2_SAVE_DIALOG_TEXT, &(_saveDialog)) == FAILURE)	
       { return FAILURE; }
    if ( CreateDialogUI(NOTEPAD2_OPEN_DIALOG_TEXT, &(_openDialog)) == FAILURE)	
       { return FAILURE; }

_saveDialog_openDialog はグローバル変数なので、"&" シンボルを使ってそのアドレスを CreateDialogUI に渡します。


同じメソッドで、FlexTextArea をフレームにアタッチした後、ユーザー インターフェイスを表示させます。 (リソース | ヘッダー | ソース)

    
    // アプリケーションのテキスト表示を作成します
    _textDisplay = theUIFactory->CreateFlexTextArea(0);
    if (_textDisplay == NULL) { return FAILURE; }
    
    // テキスト表示の属性を設定します
    _textDisplay->SetColumns(75);
    _textDisplay->SetRows(7);  
    _textDisplay->SetMaxChars(600);

    // テキスト表示をフレームに追加します
    frame->Add(_textDisplay);

    // フレームを表示し、SUCCESS を返します
    frame->SetVisible(TRUE);
    return SUCCESS;
    
} 

notepad2.cpp で、ヘルパー関数 CreateDialogUI を追加してアプリケーションのダイアログを作成します。 (リソース | ヘッダー | ソース)


Result
Notepad2App::CreateDialogUI(static const TCHAR *title, FlexDialog **dialog) {
	
    *dialog = theUIFactory->CreateFlexDialog(1, title);
    if (*dialog == NULL) { return FAILURE; }

    DialogLayout *offsetDialogLM = new DialogLayout();
    (*dialog)->SetLayout(offsetDialogLM);
    
    FlexLabel *label = theUIFactory->CreateFlexLabel(0, title);
	
    FlexList *list = theUIFactory->CreateFlexList(0, 4);
    if (list == NULL) {	return FAILURE; }
    list->SetSizingPreference(FlexComponent::SPT_USE_PREF_SIZE);
    
    if (list->Add(NOTEPAD2_FILE1) == FAILURE) { return FAILURE; }
    if (list->Add(NOTEPAD2_FILE2) == FAILURE) { return FAILURE; }
    if (list->Add(NOTEPAD2_FILE3) == FAILURE) { return FAILURE; }
    if (list->Add(NOTEPAD2_FILE4) == FAILURE) { return FAILURE; }
    
    list->AddItemListener(*this);
    
    (*dialog)->Add(label);
    (*dialog)->Add(list);
    
    this->Add(*dialog);
    return SUCCESS;
} 

DialogLayout を使用してダイアログのコンポーネントを配置します。DialogLayout はダイアログ ボックスの小さな領域を管理するために特別にデザインされたレイアウトです。

FlexList は Flex UI コンポーネントで、文字列データのリストを保持します。ここではファイル名を保持しています。FlexListFlexMenu は、FlexMenu ではメニュー ボタンを押したときにイベントが生成されるのに対して、FlexList は現在選択中の項目が変化したときにイベントが生成される点が異なります。このアプリケーションでは、FlexList を使用してテキスト バッファの保存や読み込みができるファイルを表示します。ファイルごとに FlexList メソッド Add を使用して、ファイル名をリストに追加します。

リストを作成した後で、AppBase メソッド Add を使用してダイアログをシステムにアタッチします。


notepad2.cpp に、EventHandler の MenuItemChosen を追加してメニュー イベントを処理します。 (リソース | ヘッダー | ソース)


void
Notepad2App::MenuItemChosen(MenuEvent& event )
{
    uint32 id = (uint32)event._menuItemID;
    
    if (_dialogOpen < 1) {
        switch (id) {
            
         case NEW_MENU_ITEM:
            _textDisplay->SetText(_TEXT(""));
            break;
            
         case SAVE_MENU_ITEM:
            _dialogOpen = id;
            _saveDialog->SetVisible(TRUE);
            break;
            
         case OPEN_MENU_ITEM:
            _dialogOpen = id;
            _openDialog->SetVisible(TRUE);
            break;
        }
    }
}

_menuItemID には選択中のメニュー項目の id が入ります。switch 文では id を使用してどの FlexMenuButton が選択されたかを判断し、それに応じて適切なダイアログを表示し、_dialogOpen を対応する値に設定します。


notepad2.cpp に、EventHandler の ItemStateChanged を追加してリスト イベントを処理します。 (リソース | ヘッダー | ソース)


void
Notepad2App::ItemStateChanged(ItemEvent& event )
{

    // SAVE と OPEN のためのファイル ポインタと、
    // ファイル名を格納する文字列を作成します
    File        *myFile;
    const TCHAR *filename;
    
    FlexList        *list	= (FlexList *)event.GetSource();
    uint32          index	= event.GetIndex();	
    
    switch (index) {
     case 0:
        filename = NOTEPAD2_FILE1;
        break;
     case 1: 
        filename = NOTEPAD2_FILE2;
        break;
     case 2:
        filename = NOTEPAD2_FILE3;
        break;
     case 3:
        filename = NOTEPAD2_FILE4;
        break;
    }   

メソッド GetIndex を使用して選択中の文字列に対応する番号を index に読み込みます。switch 文では、この index を使って保存や読み込みに使用するファイル名を設定します。


ファイルの Save (保存)と Revert (読み込み)のコードを ItemStateChanged に追加します。 (リソース | ヘッダー | ソース)


    // SAVE がクリックされたかどうかチェックします
    if (_dialogOpen == SAVE_MENU_ITEM)  {
	
        // バッファの内容を取得します
        _textDisplay->GetText(_notepad2TextString, 600);
        
        // ファイルを CREATE と READ_WRITE 属性で開きます
        myFile = theFileStoreManager.Open(filename, O_CREAT | O_RDWR );

        // バッファの内容をファイルへ書き込み、
        // ファイルを閉じます
        myFile->Write((uint8 *)_notepad2TextString, 600);
        myFile->Close();

        // ダイアログを閉じます
        _saveDialog->SetVisible(FALSE);
    }		

    // OPEN がクリックされたかどうかチェックします
    else if (_dialogOpen == OPEN_MENU_ITEM) {

        // ファイルがすでに存在するかどうかチェックします
        if (theFileStoreManager.FileExists(filename)) {

            // ファイルを READ_ONLY で開き、内容をバッファに読み込み、
            // 操作終了後にファイルを閉じます
            myFile = theFileStoreManager.Open(filename, O_RDONLY );
            myFile->Read((uint8 *)_notepad2TextString, 600);
            myFile->Close();

            // バッファの内容を表示します
            _textDisplay->SetText(_notepad2TextString);	
        }
        // ダイアログを閉じます
        _openDialog->SetVisible(FALSE);
    }
    // リスト項目の選択を解除します
    list->Deselect(index);	

    // ダイアログ ボックスが閉じているように設定します
    _dialogOpen = 0;
}

アプリケーションをコンパイルして実行します。


このドキュメントについて | 用語集 | アプリケーションの記述方法 | ユーザー インタラクションの検出方法 | 複数の UI の統合