前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

9.23. UI を表示する BREW インターフェース

9.23.1. BREW イベントの配信順序

SFY アプリでは、 BREW 環境から受信したイベント(以下、BREW イベント)は最初にレスポンダに配信されます。

[Note] 注意

厳密に言えば、BREW イベントは最初に アプリケーションクラス(SFYApplication を継承するクラス)が内部に保持する ルートに渡されます。 その後、トレーサの配信規則により、 ルートを頂点とするレスポンダツリー上の各レスポンダに配信されます。

9.23.2. BREW イベントを最初に BREW インターフェースの HandleEvent 関数に渡す方法

アプリが受信した BREW イベントをレスポンダよりも優先して先に渡す関数のことを 優先的イベントハンドラと呼びます。 このイベントハンドラは、SFXEventBypass::Register 関数を使用して BREW アプリ 1 つにつき 1 つまで登録可能です。

優先的イベントハンドラを登録すると、 BREW イベントは『優先的イベントハンドラレスポンダ』の順に配信されるようになります。 SFXEventBypass::Unregister 関数を呼び出してコールバックの登録が解除されるまでの間、 BREW イベントはこの順序で配信されます。

UI を表示する BREW インターフェースでは、 アプリが UI 表示中に受信した BREW イベントは最初に BREW インターフェースの HandleEvent 関数に渡す必要があります。

この処理は、 優先的イベントハンドラ内で、 アプリが受け取った BREW イベントを BREW インターフェースの HandleEvent 関数に渡すことで実現できます。

UI 表示終了時は、 その時に起動されるコールバック内で SFXEventBypass::Unregister 関数を使用して 優先的イベントハンドラの登録を解除します。

その後、SFCApplication::RenderDeviceScreen 関数を呼び出して UI 表示により変更された画面を再描画してアプリの画面を復元します (この再描画は、UI 表示終了時に起動されるコールバック内で行うこともあります)。

[Note] 優先的イベントハンドラについて

SFXEventBypass クラスの解説を参照してください。

[Note] BREW インターフェースの UI 表示終了時の処理について

優先的イベントハンドラの登録を解除すると BREW イベントは最初にレスポンダに配信される設定に戻ります。

UI 処理の結果、再描画後の画面が UI 表示前と異なる場合もあります(例: FEP からテキストを入力したとき)。

再描画は、SFCApplication::RenderDeviceScreen 関数を呼び出して行います。

[Note] BREW イベントの処理について

優先的イベントハンドラに関わる BREW イベントの処理については、 SFY アプリの全体的な処理の流れイベントループを参照してください。

[Note] 注意

BREW API ITextCtl インターフェースでは、 UI 表示終了時に呼び出されるコールバックを登録できません。

この場合は、UI 表示終了時に EVT_COMMAND イベントを受信したときに優先的イベントハンドラの登録を解除し、 SFCApplication::RenderDeviceScreen 関数を呼び出して全画面 (デバイス画面とルート以下のレスポンダツリー)を再描画します。

詳細は、 「SophiaFramework UNIVERSE での実装例: ITextCtl / IMenuCtl インターフェース」 を参照してください

9.23.3. サンプルコード

以下では、 ISampleDialog というインターフェース(C++ ラッパークラス名: SFBSampleDialog)が存在したと仮定して解説します。

  1. SFBSampleDialog::StartDialog 関数は dialog_type 引数に指定されたダイアログを表示します。
  2. SFBSampleDialog::StartDialog 関数の notify 引数にはダイアログ終了時に呼び出されるコールバックを指定します。 user 引数はコールバックに渡すデータを指定します。
  3. ダイアログ表示中、 BREW 環境から通知されたイベント(BREW イベント)は優先的に SFBSampleDialog::HandleEvent 関数に渡す必要があります。
class SFBSampleDialog : public SFBBase {
    SFMSEALWRAPPER(SFBSampleDialog)
    SFMWRAPPERINSTANTIATEONE(SFBSampleDialog, SFBBase)
    public:
        static  SFBSampleDialogSmp NewInstance (SFCErrorPtr exception = null);
        static  SFBSampleDialogSmp NewInstance (AEECLSID id, SFCErrorPtr exception = null);
                Bool               HandleEvent (AEEEvent evt, UInt16 wp, UInt32 dwp);
                SFCError           StartDialog (UInt32 dialog_type, PFNDLGCB notify, VoidPtr user);
};


// notify 引数に指定するダイアログ終了時に呼び出されるコールバックの型
Typedef SIntN(* PFNDLGCB)(VoidPtr reference, SIntN error);

// dialog_type 引数に指定するダイアログの種類
#define DIALOG_A 0
#define DIALOG_B 1
#define DIALOG_C 2

SFY アプリ内で SFBSampleDialog クラスを使用するには、 SFBSampleDialog::StartDialog 関数を実行してダイアログを表示した後はダイアログを終了するまでの間、 BREW イベントはレスポンダよりも先に SFBSampleDialog::HandleEvent 関数に渡す必要があります。

これを実現するために、 以下の SophiaDialog クラスを定義、実装します。

class SophiaDialog  {
    SFMSEALCOPY(SophiaDialog)
    public:
        typedef SFCError                   (*CallbackSPP)       (SFCError error, VoidPtr reference);
        SFMTYPEDEFTYPE(CallbackSPP)

    private:
                SFBSampleDialogSmp         _dialog;
                CallbackSPP                _callback;
                VoidPtr                    _reference;
    public:
        explicit                           SophiaDialog         (Void);
        virtual                            ~SophiaDialog        (Void);
                SFBSampleDialogSmpConstRef GetSFBSampleDialog   (Void) const;
                SFCError                   StartDialog          (UInt32 dialog_type, CallbackSPP callback, VoidPtr reference);
                Void                       Close                (Void);
    private:
        static  SIntN                      OnDialogResultSCP    (VoidPtr reference, SIntN error);
                SFCError                   OnDialogResult       (SFCError error);

                XALLBACK_DECLARE_SFCAPPLICATION(OnDialogEventBypass)
};


// コンストラクタ
/*public */SFXDialog::SFXDialog(Void) : _callback(null), _reference(null)
{
}// SFXDialog::SFXDialog //

// デストラクタ
/*public virtual*/SFXDialog::~SFXDialog(Void)
{
    Close();
}// SFXDialog::~SFXDialog //

SophiaDialog::StartDialog 関数では、 SFXEventBypass::Register 関数を使用して SophiaDialog::OnDialogEventBypass 優先的イベントハンドラを登録してから SFBSampleDialog::StartDialog 関数を呼び出しています。

SophiaDialog::OnDialogEventBypass 優先的イベントハンドラでは、 最初に SFBSampleDialog::HandleEvent 関数に BREW イベントを渡しています。

SFBSampleDialog::StartDialog 関数の第 2 引数に指定している SophiaDialog::OnDialogResultSCP 関数はダイアログ終了時に起動されるコールバックです。

// SophiaDialog::OnDialogEventBypass 優先的イベントハンドラを登録してダイアログを表示する関数
/*public */SFCError SophiaDialog::StartDialog(UInt32 dialog_type, CallbackSPP callback, VoidPtr reference)
{
    SFCError                                    error;

    if ((_dialog = SFBSampleDialog::NewInstance(&error)) != null) {

        // SophiaDialog::OnDialogEventBypass 優先的イベントハンドラを登録する
        if ((error = SFXEventBypass::Register(XALLBACK_INTERNAL(OnDialogEventBypass))) == SFERR_NO_ERROR) {

            // OnDialogResultSCP 関数の最後に呼び出されるコールバック
            _callback = callback;
            _reference = reference;

            // UI 表示終了時に起動されるコールバックを指定してダイアログを表示する
            error = _dialog->StartDialog(dialog_type, OnDialogResultSCP, this);
        }
    }
    if (error != SFERR_NO_ERROR) {

        Close();
    }
    return error;
}// SophiaDialog::StartDialog //

// SophiaDialog::OnDialogEventBypass 優先的イベントハンドラ: BREW イベントが優先的に通知される関数
/*private */XALLBACK_IMPLEMENT_SFCAPPLICATION(SophiaDialog, OnDialogEventBypass, event)
{
    Bool result(false);

    // BREW イベントは優先的に SFBSampleDialog::HandleEvent 関数に通知される
    result = _dialog->HandleEvent(event.GetType(), event.GetP16(), event.GetP32());

    switch (event.GetType()) {

        case SFEVT_APP_RESUME:
            result = true;
            break;

        case SFEVT_APP_STOP:
        case SFEVT_APP_SUSPEND:
            Close();
            result = true;
            break;

        case SFEVT_KEY:
        case SFEVT_KEY_PRESS:
        case SFEVT_KEY_RELEASE:
        #if TARGET_VERSION_LT(3, 0, 0)
        case SFEVT_KEY_HELD:
        #endif
            result = true;
            break;

        default:
            break;
    }

    return result;
}// XALLBACK_IMPLEMENT_SFCAPPLICATION(SophiaDialog, OnDialogEventBypass) //

SophiaDialog::OnDialogResultSCP 関数では、 SophiaDialog::Close 関数を呼び出して SophiaDialog::OnDialogEventBypass 優先的イベントハンドラの登録を解除します。

また、SophiaDialog::OnDialogResultSCP 関数の最後で呼び出される、 SophiaDialog::StartDialog 関数の引数に指定したコールバック内では、 SFCApplication::RenderDeviceScreen 関数を呼び出して UI 表示により変更された画面を再描画します。

// ダイアログ終了時に呼び出されるコールバック
/*private static*/SIntN SophiaDialog::OnDialogResultSCP(VoidPtr reference, SIntN error)
{
    return SophiaDialogPtr(reference)->OnDialogResult(error);
}// SophiaDialog::OnDialogResultSCP //

/*private */SFCError SophiaDialog::OnDialogResult(SFCError error)
{
    SFCApplicationPtr application;

    // 優先的イベントハンドラの登録を解除する(ダイアログ表示の終了処理を行う)
    Close();
    if (_callback != null) {

        // ダイアログ表示終了時に起動されるコールバック
        // ※SophiaDialog::StartDialog 関数の引数に指定されたコールバックを起動する
        error = _callback(error, _reference);
    }
    // 全画面を再描画する
    if ((application = SFCApplication::GetInstance()) != null) {
        application->RenderDeviceScreen();
    }
    return error;
}// SophiaDialog::OnDialogResult //


// ダイアログ表示の終了処理を行う関数
/*private */Void SophiaDialog::Close(Void)
{

    // SophiaDialog::OnDialogEventBypass 優先的イベントハンドラの登録を解除する
    SFXEventBypass::Unregister(XALLBACK_INTERNAL(OnDialogEventBypass));

    // ダイアログを解放する
    _dialog.Release();

    return;
}// SophiaDialog::Close //

以下は、実際に SophiaDialog クラスを利用して ISampleDialog インターフェース(SFBSampleDialog クラス)のダイアログを表示するコードです。

class sampleapp : SFYApplication {
    SFMSEALCOPY(sampleapp)
public:
    static SFCInvokePtr Factory(Void);
private:
    SophiaDialog _dialog;  // SFYApplication 継承するアプリケーションクラスのメンバ変数として定義する
private:
    explicit sampleapp(Void) static_throws;
    virtual ~sampleapp(Void);
private:
    // ダイアログ終了時に呼び出されるコールバック(エントリ)
    static  SFCError   OnDialogResultSCP(VoidPtr reference, SFCError error);
    // ダイアログ終了時に呼び出されるコールバック(実体)
            SFCError   OnDialogResult(SFCError error);
};

// コンストラクタ
sampleapp::sampleapp(Void) static_throws
{
    if (static_try()) {

        // ダイアログ DIALOG_A を表示する
        static_throw(_dialog->StartDialog(DIALOG_A, OnDialogResultSCP, this);
    }
}

// デストラクタ
sampleapp::~sampleapp(Void)
{
}

// ダイアログ終了時に呼び出されるコールバック(エントリ)
/*private static*/SFCError sampleapp::OnDialogResultSCP(VoidPtr reference, SFCError error)
{
    return sampleappPtr(reference)->OnDialogResult(error);
}// sampleapp::OnDialogResultSCP //

// ダイアログ終了時に呼び出されるコールバック(実体)
/*private */SFCError sampleapp::OnDialogResult(SFCError error)
{
    TRACE("... OnDialogResult: %X", error);

    return error;
}// sampleapp::OnDialogResult//

9.23.4. SophiaFramework UNIVERSE における FEP の制御

9.23.4.1. 概要

SFZSingleEditLabelControl など名前に "Edit" を含むレスポンダクラスでは、 以下のようにしてテキスト入力を行います(FEP を制御します)。

  1. BREW API ITextCtl インターフェースと BREW API IMenuCtl インターフェースを使用します。
  2. FEP を起動すると、 FEP が終了するまでの間、 BREW イベントは優先的に BREW API ITEXTCTL_HandleEvent 関数に通知されます。
  3. FEP が終了すると、 BREW イベントは優先的にレスポンダに通知されるように、 イベント配信順序を元に戻します。 同時に、FEP によって変更された画面を再描画します。
  4. 画面の再描画以外はすべて SFXEditor クラスで行われます。
[Note] 注意

SFZSingleEditLabelControl クラスのすべての実装コードは、 fep_for_sf2.zip にあります(関連コードも含まれます)。

9.23.4.2. FEP の起動と優先的イベントハンドラの登録

SFXEditor クラスは、 FEP の各種プロパティの設定や、起動と終了の処理をカプセル化したクラスです。

このクラスは、SFYSingleEditWidget / SFYMultipleEditWidget クラスの内部で使用されます。

SFXEditor::Open 関数は、 各種プロパティの設定を行ってから FEP を起動します。

下記の実装コードにあるように、 SFXEventBypass::Register 関数を使用して OnBypass() 優先的イベントハンドラの登録も行います。

OnBypass() 優先的イベントハンドラでは、 アプリが受信した BREW イベントを最初に BREW API ITEXTCTL_HandleEvent 関数に通知する処理や、 FEP 終了時には SFXEditor::Open 関数の引数に指定された コールバックを呼び出す処理などが行われます。

#define     ITEM_NAME   ("Done")
#define     LABEL_OK      1

// FEP を起動する。FEP 終了時は、spp / reference 引数に指定されたコールバックが起動される
/*public virtual*/SFCError SFXEditor::Open(SFXEditPropertyPtr property, CallbackSPP spp, VoidPtr reference)
{
    SFBDisplaySmp                               display;
    SFXWideString                               string;
    SFXRectangle                                remember;
    SFXRectangle                                rectangle;
    UInt32                                      flag;
    SFCError                                    error(SFERR_NO_ERROR);

    if (property != null) {
        _property = property;
        if ((display = SFBDisplay::GetInstance()) != null) {

            // クリッピング領域を退避する
            display->GetClipRect(&remember);

            // クリッピング領域を空の矩形にすることにより、ITextCtl インターフェースは画面に描画できなくなる
            display->SetClipRect(SFXRectangle::EmptyInstance());

            // ITextCtl インターフェースのインスタンスを生成する
            if ((_textctl = SFBTextCtl::NewInstance(GetSFBTextCtlClassID(), &error)) != null) {

                // IMenuCtl インターフェースのインスタンスを生成する
                if ((_menuctl = SFBMenuCtl::NewInstance(GetSFBMenuCtlClassID(), &error)) != null) {

                    if ((error = string.Set(ITEM_NAME)) == SFERR_NO_ERROR) {

                        // IMenuCtl インターフェースに項目を追加する
                        // ※FEP 終了時に通知される SFEVT_COMMAND イベントの P16 パラメータは LABEL_OK となる
                        if (_menuctl->AddItem(LABEL_OK, &string, reinterpret_cast<UInt32>(_menuctl.Get()))) {

                            // ITextCtl インターフェースの各種プロパティを設定する

                            // ITextCtl インターフェースに IMenuCtl インターフェースを関連付ける
                            _textctl->SetSoftKeyMenu(_menuctl);

                            // ITextCtl インターフェース自身が描画されない設定を行う
                            flag = TP_NODRAW | TP_FRAME | TP_NOUPDATE | TP_FIXSETRECT;
                            if (_property->GetPasswordMode()) {
                                flag |= TP_PASSWORD;
                            }
                            _textctl->SetProperties(flag);
                            rectangle.Set(SFXGrid::ZeroInstance(), SFXDevice().GetScreenSize());
                            rectangle.SubBottom(_menuctl->GetRect().GetHeight());
                            _textctl->SetRect(rectangle);
                            _textctl->SetMaxSize(_property->GetMaximumLength());
                            _textctl->SetInputMode(_property->GetInputMode());
                            if (_textctl->SetText(_property->GetText())) {

                                // 優先的イベントハンドラを登録する
                                // ※FEP 起動中、BREW イベントは優先的に SFXEditor::OnBypass 優先的イベントハンドラに通知される
                                if ((error = RegisterBypass(XALLBACK_INTERNAL(OnBypass))) == SFERR_NO_ERROR) {

                                    // FEP 終了時に起動されるコールバックを設定する
                                    _spp = spp;
                                    _reference = reference;
                                }
                            }
                            else {
                                error = SFERR_FAILED;
                            }
                        }
                        else {
                            error = SFERR_FAILED;
                        }
                    }
                }
            }
            if (error != SFERR_NO_ERROR) {
                Close();
            }
            // クリッピング領域を復元する
            display->SetClipRect(remember);

            if (error == SFERR_NO_ERROR) {
                _textctl->SetActive(true);
                _textctl->SetCursorPos(TC_CURSORSTART);
            }
        }
        else {
            error = SFERR_FAILED;
        }
    }
    else {
        error = SFERR_INVALID_PARAM;
    }
    return error;
}// SFXEditor::Open //

// SFXEditor::OnBypass 優先的イベントハンドラ: BREW イベントが優先的に通知される関数
/*private */XALLBACK_IMPLEMENT_SFCAPPLICATION(SFXEditor, OnBypass, event)
{
    SFXWideString  string;
    SFCError       error;
    Bool           result(false);

    // アプリが受信した BREW イベントを最初に ITEXTCTL_HandleEvent 関数に通知する
    result = _textctl->HandleEvent(event);
    switch (event.GetType()) {

        case SFEVT_APP_RESUME:
            result = true;
            break;

        case SFEVT_APP_SUSPEND:
            result = true;
            break;

        case SFEVT_KEY:
        case SFEVT_KEY_PRESS:
        case SFEVT_KEY_RELEASE:
            result = true;
            break;

        case SFEVT_COMMAND:

            // FEP 終了時、SFEVT_COMMAND イベント(P16 パラメータ="LABEL_OK")が通知される

            if (!result) {
                switch (event.GetP16()) {

                    case LABEL_OK: // FEP が終了したとき
                        
                        // FEP にて入力されたテキストを取得する
                        if ((error = string.Set(_textctl->GetTextPtr())) == SFERR_NO_ERROR) {
                            if ((error = _property->SetText(string)) == SFERR_NO_ERROR) {
                                _property->SetInputMode(_textctl->GetInputMode());
                            }
                        }
                        // FEP を閉じる
                        Close();
                        if (_spp != null) {

                            // FEP 終了時に起動されるコールバック
                            // ※1. SFXEditor::Open 関数の引数に指定したコールバック
                            // ※2. このコールバックでは FEP から入力されたテキストをレスポンダに反映させる
                            (*_spp)(error, _reference);
                        }
                        // 全画面(デバイス画面とルート以下のレスポンダツリー)を再描画する
                        if ((application = SFCApplication::GetInstance()) != null) {
                            application->RenderDeviceScreen();
                        }
                        break;

                    default:
                        break;
                }
                result = true;
            }
            break;
        default:
            break;
    }
    return result;
}// XALLBACK_IMPLEMENT_SFCAPPLICATION(SFXEditor, OnBypass) //

// FEP の終了処理
/*public */Void SFXEditor::Close(Void)
{
    if (_textctl != null) {
        _textctl->SetSoftKeyMenu(SFBMenuCtlSmp::EmptyInstance());
        _textctl->SetActive(false);
    }
    // SFXEditor::OnBypass 優先的イベントハンドラの登録を解除する
    UnregisterBypass(XALLBACK_INTERNAL(OnBypass));

    // ITextCtl / IMenuCtl インターフェースを解放する
    _menuctl.Release();
    _textctl.Release();
    _property = null;
    return;
}// SFXEditor::Close //

SFXBaseEditor::RegisterBypass 関数の内部実装は、以下の通りです (SFXEventBypass::Register 関数を呼び出します)。

// 優先的イベントハンドラを登録する
/*protected static*/inline SFCError SFXBaseEditor::RegisterBypass(SFCApplication::CallbackSPP spp, VoidPtr reference)
{
    return SFXEventBypass::Register(spp, reference);
}// SFXBaseEditor::RegisterBypass //

SFXBaseEditor::UnregisterBypass 関数の内部実装は、以下の通りです (SFXEventBypass::Unregister 関数を呼び出します)。

// 優先的イベントハンドラの登録を解除する
/*protected static*/inline SFCError SFXBaseEditor::UnregisterBypass(SFCApplication::CallbackSPP spp, VoidPtr reference)
{
    SFXEventBypass::Unregister(spp, reference);
}// SFXBaseEditor::UnregisterBypass //

9.23.4.3. レスポンダクラスからの FEP の起動と終了時の再描画

SFZSingleEditLabelControl クラスは、 内部で保持する SFYSingleEditWidget クラスの SFYSingleEditWidget::Edit 関数を呼び出すことにより FEP を起動してその結果を取得します

SFYSingleEditWidget::Edit 関数の内部実装は以下の通りです。

// FEP に遷移し、FEP の入力結果を取得する関数
/*public */SFCError SFYSingleEditWidget::Edit(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((error = _property.SetMaximumLength(_maximum)) == SFERR_NO_ERROR) {
        if ((error = _property.SetText(_text)) == SFERR_NO_ERROR) {

            // SFXEditor::Open 関数を呼び出して FEP を起動する
            // ※ SFYSingleEditWidget::OnEditor 関数は FEP 終了時に起動されるコールバック
            //(このコールバックでは、FEP から入力されたテキストを取得し、SFEVT_RESPONDER_RESULT イベントを自分自身に送信する)
            error = _editor->Open(&_property, XALLBACK_INTERNAL(OnEditor));
        }
    }
    return error;
}// SFYSingleEditWidget::Edit //

SFYSingleEditWidget::Edit 関数では、 SFXEditor::Open 関数を呼び出して FEP を起動します。 引数に指定している SFYSingleEditWidget::OnEditor 関数は FEP 終了時に呼び出されます。

SFYSingleEditWidget::OnEditor 関数の内部実装は以下の通りです。

class SFYSingleEditWidget : public SFYWidget {
    SFMSEALRESPONDER(SFYSingleEditWidget)
    SFMRESPONDERINSTANTIATETWO(SFYSingleEditWidget, SFYWidget, SFYResponder)

    // ...(省略)...
    private:
                SFYSingleTextWidgetSmp          _widget;
                SFXBaseEditorPtr                _editor;
                SFXEditProperty                 _property;
                SFXWideString                   _text;
                UInt16                          _maximum;

    // ...(省略)...
}

// FEP 終了時に起動されるコールバック
// ※FEP から入力されたテキストを取得し、SFEVT_RESPONDER_RESULT イベントを自分自身に送信する
/*private */XALLBACK_IMPLEMENT_SFXEDITOR(SFYSingleEditWidget, OnEditor, context)
{
    SFYResponderSmp                             root;
    SFCError                                    error;

    if ((error = context) == SFERR_NO_ERROR) {

        // FEP にて入力されたテキストを取得し、内部で保持する SFYSingleTextWidget クラスに設定する
        if ((error = SetTextMaximumLength(_property.GetText(), _property.GetMaximumLength())) == SFERR_NO_ERROR) {

            // SFYSingleEditWidget クラスに SFEVT_RESPONDER_RESULT イベントを送信する
            InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_OK, 0), false);
        }
    }
    if (error != SFERR_NO_ERROR) {

        // SFYSingleEditWidget クラスに SFEVT_RESPONDER_RESULT イベントを送信する
        InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_ERROR, error), false);
    }
    return;
}// XALLBACK_IMPLEMENT_SFXEDITOR(SFYSingleEditWidget, OnEditor) //

SFXEditor::OnBypass 関数内で FEP 終了時に呼び出す SFCApplication::RenderDeviceScreen 関数の処理により、 全画面(デバイス画面とルート以下のレスポンダツリー)の再描画が行われます (この再描画では、FEP から入力されたテキストの情報も反映されます)。

SFYSingleEditWidget::SetTextMaximumLength 関数では、 FEP にて取得したテキストを SFYSingleEditWidget::Edit クラスが内部に保持する SFYSingleTextWidget クラスに設定しています。

/*private */SFCError SFYSingleEditWidget::SetTextMaximumLength(SFXWideStringConstRef text, UInt16 maximum)
{
    SFXWideString                               string;
    SFXWideString                               temp;
    SFCError                                    error(SFERR_NO_ERROR);

    if (!text.Equals(_text) || maximum != _maximum) {

        if ((error = string.Set(text.Substring(0, maximum))) == SFERR_NO_ERROR) {

            if (!string.Equals(_text)) {

                if ((error = temp.Set(_text)) == SFERR_NO_ERROR) {

                    if ((error = _text.Set(string)) == SFERR_NO_ERROR) {

                        // テキストを内部で保持する SFYSingleTextWidget クラスに設定する
                        if ((error = SetWidgetText(_text, _property.GetPasswordMode())) == SFERR_NO_ERROR) {

                            _maximum = maximum;
                            Invalidate();
                            InvokeBackward(SFXEvent(SFEVT_RESPONDER_STYLE, SFP16_STYLE_TEXT, 0), true);
                        }
                        else if (temp.IsEmpty()) {

                            _text.Clear();
                        }
                        else if (_text.Attach(&temp) != SFERR_NO_ERROR) {

                            _text.Clear();
                            Invalidate();
                            InvokeBackward(SFXEvent(SFEVT_RESPONDER_STYLE, SFP16_STYLE_TEXT, 0), true);
                        }
                    }
                }
            }
            else if (maximum != _maximum) {

                _maximum = maximum;
                Invalidate();
            }
        }
    }
    return error;
}// SFYSingleEditWidget::SetTextMaximumLength //

/*private */SFCError SFYSingleEditWidget::SetWidgetText(SFXWideStringConstRef text, Bool password)
{
    SFXWideString                               string;
    SFCError                                    error(SFERR_NO_ERROR);

    if (password) {
        if ((error = string.Set(text)) == SFERR_NO_ERROR) {

            error = SFXShiftJIS::ToPassword(&string);
            if (error == SFERR_NO_ERROR) {

                // テキストを内部で保持する SFYSingleTextWidget クラスに設定する
                error = _widget->SetText(string);
            }
        }
    }
    else {

        error = _widget->SetText(text);
    }
    return error;
}// SFYSingleEditWidget::SetWidgetText //
[Note] 注意

FEP から入力されたテキストは、 最終的に SFYSingleTextWidget クラスのプロパティとなり、 このクラスにより描画されます。

9.23.4.4. SFZSingleEditLabelControl クラスでの処理

SFZSingleEditLabelControl クラスは、 内部に SFYSingleEditWidget クラスを保持しています。

SFZSingleEditLabelControl クラスでは、 コンストラクタ内で SFYSingleEditWidget クラスが SFEVT_RESPONDER_RESULT イベントを受信した場合、 SFZSingleEditLabelControl::OnWidgetResult 関数を起動し、 SFZSingleEditLabelControl クラスに SFEVT_RESPONDER_RESULT イベントを送信する処理を行います。

class SFZSingleEditLabelControl : public SFYLabelControl {
    SFMSEALRESPONDER(SFZSingleEditLabelControl)
    SFMRESPONDERINSTANTIATEFOUR(SFZSingleEditLabelControl, SFYLabelControl, SFYControl, SFYWidget, SFYResponder)

    // ...(省略)...
    private:
                SFYSingleEditWidgetSmp  _widget;

    // ...(省略)...
}

/*protected */SFZSingleEditLabelControl::SFZSingleEditLabelControl(Void) static_throws
{
    static SFXEventRange::AtomRecConst          trange[] = {
        { SFEVT_RESPONDER_STATE,  SFEVT_RESPONDER_STATE,    SFP16_STATE_FOCUS,    SFP16_STATE_FOCUS}
    };
    static SFXEventRange::AtomRecConst          crange[] = {
        { SFEVT_RESPONDER_STYLE,  SFEVT_RESPONDER_STYLE,          SFP16_BEGIN,            SFP16_END},
        {SFEVT_RESPONDER_RESULT, SFEVT_RESPONDER_RESULT,          SFP16_BEGIN,            SFP16_END}
    };
    SFYHandler::RuleRec                         trule[lengthof(trange)];
    SFYHandler::RuleRec                         crule[lengthof(crange)];
    SFCError                                    error;

    if (static_try()) {

        SetType(CODE_TYPE);
        trule[0].spp = XANDLER_FUNCTION(OnStateFocus);
        trule[0].reference = this;
        static_throw(RegisterHandler(atomic_cast(trange), trule, lengthof(trange)));
        if (static_try()) {

            if ((_widget = SFYSingleEditWidget::NewInstance(&error)) != null) {

                // SFEVT_RESPONDER_STYLE イベントのハンドラ
                crule[0].spp = XANDLER_FUNCTION(OnWidgetStyle);
                crule[0].reference = this;

                // SFEVT_RESPONDER_RESULT イベントのハンドラ
                crule[1].spp = XANDLER_FUNCTION(OnWidgetResult);
                crule[1].reference = this;

                // SFYSingleEditWidget クラスへのイベントハンドラの登録
                static_throw(_widget->RegisterHandler(atomic_cast(crange), crule, lengthof(crange)));
                if (static_try()) {

                    static_throw(_widget->SetParent(GetThis()));
                    if (static_try()) {

                        SetPropertyTransparent(true);
                        _widget->SetState(true, true, false, false);
                        Relocate();
                    }
                }
            }
            else {

                static_throw(error);
            }
        }
    }
}// SFZSingleEditLabelControl::SFZSingleEditLabelControl //

// SFYSingleEditWidget クラスが SFEVT_RESPONDER_RESULT イベントを受信したときに呼び出されるハンドラ
/*private */XANDLER_IMPLEMENT_VOIDRESULT(SFZSingleEditLabelControl, OnWidgetResult, invoker, reason, result)
{
    unused(invoker);
    switch (reason) {

        case SFP16_RESULT_OK:

            result = GetCurrentValue();
            break;

        default:

            break;
    }
    _widget->StartScroll();

    // SFZSingleEditLabelControl クラスに SFEVT_RESPONDER_RESULT イベントを送信する
    InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, reason, result), false);

    return;
}// XANDLER_IMPLEMENT_VOIDRESULT(SFZSingleEditLabelControl, OnWidgetResult) //

SFZSingleEditLabelControl::HandleOperateKey 関数は、 SFZSingleEditLabelControl クラスの操作キーイベントを受信したときに呼び出されます。

この関数では、以下の内部実装コードにあるように SFYSingleEditWidget::Edit 関数を呼び出して FEP を起動します。

FEP 終了時に SFYSingleEditWidget クラスは SFEVT_RESPONDER_RESULT イベントを受信し、 SFZSingleEditLabelControl::OnWidgetResult ハンドラ関数が起動され、 SFZSingleEditLabelControl クラスも SFEVT_RESPONDER_RESULT イベントを受信することになります。

// SFZSingleEditLabelControl クラスが操作キーのイベントを受信したときのハンドラ関数
/*protected virtual */Void SFZSingleEditLabelControl::HandleOperateKey(Void)
{
    SFCError                                    error;

    _widget->StopScroll();

    // FEP に遷移する
    if ((error = _widget->Edit()) != SFERR_NO_ERROR) {

        _widget->StartScroll();
        InvokeForward(SFXEvent(SFEVT_RESPONDER_RESULT, SFP16_RESULT_ERROR, error), false);
    }
    return;
}// SFZSingleEditLabelControl::HandleOperateKey //