ホーム > 製品情報 > SophiaFramework UNIVERSE > チュートリアル > BREW vCalendar スケジューラー

BREW スケジューラー 〜 BREW C++ vCalendar プログラミング 〜

キーの処理

MainWindow

カレンダーを描画する MainWindow では、現在のカーソルの位置を SFXDate (日付) 型の変数である _cursor に記憶しています。

class MainWindow : public SFRPlainWindow {
private:
    SFXDate _cursor; // カーソルの位置
    // 以下省略
};

キーハンドラ

HANDLER_IMPLEMENT_BOOLEVENT(MainWindow, OnKey, event)
{
    Bool result(false);

    switch (event.GetP16()) {
        case AVK_SELECT: // セレクトキーが押されたら
            ::new OneDayWindow(_cursor);
            result = true;
            break;
        case AVK_LEFT:
            _cursor.SubDay(1); // カーソルを左へ (1日引く)
            InvalidateContent(); // 再描画
            result = true;
            break;
        case AVK_RIGHT:
            _cursor.AddDay(1); // カーソルを右へ (1日加える)
            InvalidateContent(); // 再描画
            result = true;
            break;
        case AVK_UP:
            _cursor.SubDay(7); // カーソルを上へ (1週間引く)
            InvalidateContent(); // 再描画
            result = true;
            break;
        case AVK_DOWN:
            _cursor.AddDay(7); // カーソルを下へ (1週間加える)
            InvalidateContent(); // 再描画
            result = true;
            break;
    }
    return result;
}

OneDayWindow

OneDayWindow は一日の全予定を表示します。

1 行目は新規データ作成用に「新規」の文字が、2 行目以降はその日のカレンダーデータの時刻と summary フィールド ( 内容 ) が表示されます。

SFMTYPEDEFCLASS(OneDayWindow)
class OneDayWindow : public SFRPlainWindow {
    SFMSEALCOPY(OneDayWindow)
private:
    SInt16 _displine; // 表示する行の先頭
    SInt16 _cursor;   // カーソル位置
    SInt16 _maxline;  // 表示する行数
    SFXDateConst _date; // その日の日付
    // _date の日付の先頭の VCalendar が何番目か
    SInt32 _index;
    // _date の日付の VCalendar の個数
    SInt32 _number;
public:
    OneDayWindow(SFXDateConstRef date) static_throws;
    virtual ~OneDayWindow(Void);
    HANDLER_DECLARE_VOIDRENDER(OnRenderContent) // 描画ハンドラ
    HANDLER_DECLARE_BOOLEVENT(OnKey) // キーハンドラ
};

_cursor 変数 : 0 のときは「新規」、1 以上のときはその日のカレンダーデータ

キーハンドラ

HANDLER_IMPLEMENT_BOOLEVENT(OneDayWindow, OnKey, event)
{
    Bool result(false);
    switch (event.GetP16()) {
        case AVK_CLR: // クリアー キーが押されたら、
            // ウィンドウを閉じる
            result = Invoke(SFXEvent(SREVT_RESPONDER_TERMINATE,
                SRP16_TERMINATE_INVOKE, true));
            break;
        case AVK_SELECT:
            if (_cursor <= 0) { //新規作成なら
                ::new CreateWindow(_date); // ウィンドウを生成
            } else { // そうでないならカーソルが指しているデータを渡す
                // カーソルが指しているデータ
                VCalendarFilePtr vcal =
                    SyncScheduler::GetVCalCollection()->Get(
                        _index + _displine + _cursor - 1);
                ::new ModifyWindow(_date, vcal); // ウィンドウを生成
            }
            result = true;
            break;
        case AVK_DOWN:
            // カーソルがデータの一番下にないなら
            if (_cursor + _displine < _number) {
                // カーソルが画面の一番下にあるなら
                if (_cursor >= _maxline - 1) {
                    ++_displine; // 表示行を下へ
                } else {
                    ++_cursor; // カーソルを下へ
                }
            }
            else { // カーソルが最下段なら
                // カーソルを最上段へ
                _displine = 0;
                _cursor = 0;
            }
            InvalidateContent(); // 再描画
            result = true;
            break;
        case AVK_UP:
            if (_cursor == 0) { // カーソルが一番上にあるなら
                if (_displine > 0) { // 表示行を上へ動かせるなら
                    --_displine; // 表示行を上へ動かす
                }
                else { // カーソルが最上段なら
                    // カーソルを最下段へ
                    _cursor = (_number < _maxline - 1) ?
                            _number : _maxline - 1;
                    _displine = (_number > _maxline - 1) ?
                            (_number - _maxline + 1) : 0;
                }
            } else {
                --_cursor; // カーソルを上へ
            }
            InvalidateContent(); // 再描画
            result = true;
            break;
    }
    return result;
}

DataInputWindow

データの新規入力画面の CreateWindow とデータ修正画面の ModifyWindow は、処理内容がほとんど同じなので、どちらも DataInputWindow を継承しています。

SFMTYPEDEFCLASS(DataInputWindow)
class DataInputWindow : public SFRPlainWindow {
    SFMSEALCOPY(DataInputWindow)
protected:
    SFRBrewTextControlPtr _textHour;    // 時間入力テキストコントロール
    SFRBrewTextControlPtr _textMinute;  // 分入力テキストコントロール
    SFRBrewTextControlPtr _textContent; // 内容入力テキストコントロール
    SFRButtonControlPtr _buttonOk; // OK ボタン
    SFRButtonControlPtr _buttonCancel; // キャンセルボタン
    SFRLabelControlPtr _labelDate;   // 日時ラベル
    SFRLabelControlPtr _labelHour;   // 時間ラベル
    SFRLabelControlPtr _labelMinute; // 分ラベル
    SInt16 _fontHeight; // フォントの高さ
    SFXDateConst _date; // 今日の日付
public:
    DataInputWindow(SFXDateConstRef date) static_throws;
    virtual ~DataInputWindow(Void);
    virtual Void MakeData(SFXDateConstRef start,
        SFXAnsiStringConstRef summary) = 0;

    HANDLER_DECLARE_VOIDRENDER(OnRenderContent) // 描画ハンドラ
    HANDLER_DECLARE_BOOLEVENT(OnKey) // キーハンドラ
    HANDLER_DECLARE_VOIDCONTROL(OnOkButtonControl) // ボタンハンドラ
    HANDLER_DECLARE_VOIDCONTROL(OnCancelButtonControl) // ボタンハンドラ
};

SFMTYPEDEFCLASS(CreateWindow)
class CreateWindow : public DataInputWindow {
    SFMSEALCOPY(CreateWindow)
public:
    CreateWindow(SFXDateConstRef date);
    virtual Void MakeData(SFXDateConstRef start, SFXAnsiStringConstRef summary);
};

SFMTYPEDEFCLASS(ModifyWindow)
class ModifyWindow : public DataInputWindow {
    SFMSEALCOPY(ModifyWindow)
private:
    VCalendarFilePtr _vcal; // 修正するデータを保持
public:
    ModifyWindow(SFXDateConstRef date, VCalendarFilePtr vcal);
    virtual Void MakeData(SFXDateConstRef start, SFXAnsiStringConstRef summary);
};

コンストラクタ ( 抜粋 )

DataInputWindow::DataInputWindow(SFXDateConstRef date)
{
    // フォントの高さを取得
    _fontHeight = SFXGraphics::GetFontHeight(AEE_FONT_NORMAL);
    SFXRectangleConst screenRect(GetContentWorld());
    SFXRectangle rect(MENU_SIDE_MARGIN, MENU_TOP_MARGIN,
        screenRect.GetRight() - MENU_SIDE_MARGIN, _fontHeight); //長方形

    // ラベルの生成
    _labelDate = ::new SFRLabelControl(this, rect, date.Format("YYYY年MM月DD日"));
    rect.AddY(_fontHeight + MENU_SPACE);
    rect.SetSize(MENU_BOX_WIDTH, _fontHeight + TEXTBOX_REVISING);

    // 時間入力テキストコントロールの生成
    _textHour = ::new SFRBrewTextControl(this, rect, "");
    rect.AddX(MENU_BOX_WIDTH);

    // ラベルの生成
    _labelHour = ::new SFRLabelControl(this, rect, "時");
    rect.AddX(rect.GetWidth());

    // 分入力テキストコントロールの生成
    _textMinute = ::new SFRBrewTextControl(this, rect, "");
    rect.AddX(MENU_BOX_WIDTH);

    // ラベルの生成
    _labelMinute = ::new SFRLabelControl(this, rect, "分");
    rect.SetX(MENU_SIDE_MARGIN);
    rect.AddY(_fontHeight + MENU_SPACE + TEXTBOX_REVISING);
    rect.SetSize(screenRect.GetRight() - 2 * MENU_SIDE_MARGIN,
        screenRect.GetBottom() - 4 * MENU_SPACE
            - 3 * _fontHeight - MENU_TOP_MARGIN);

    // 内容入力テキストコントロールの生成
    _textContent = ::new SFRBrewTextControl(this, rect, "");
    rect.Set(MENU_SIDE_MARGIN, screenRect.GetBottom() - MENU_SPACE - _fontHeight,
        MENU_BUTTON_WIDTH, _fontHeight);

    // 決定ボタンの生成
    _buttonOk = ::new SFRButtonControl(this, rect, "決定");
    rect.AddX(MENU_SPACE + MENU_BUTTON_WIDTH);

    // キャンセルボタンの生成
    _buttonCancel = ::new SFRButtonControl(this, rect, "取消");

    if (static_try()) {
        // キーハンドラの登録
        static_throw(RegisterHandler(SFEVT_KEY, AVK_SELECT,
            HANDLER_AFTER, HANDLER_FUNCTION(SelectHandler)));
        if (static_try()) {
            if (_textHour != null && _textMinute != null && _textContent != null) {
                // 最大文字数設定
                _textHour->SetMaxSize(2);
                _textMinute->SetMaxSize(2);
                _textContent->SetMaxSize(255);
                // フォーカスをあてる
                _textHour->SetStatusFocus(true);
                if (static_try()) {
                    if (_buttonOk != null) {
                        // ボタンハンドラの登録
                        static_throw(_buttonOk->RegisterHandler(SREVT_CONTROL, 
                            HANDLER_BEFORE,HANDLER_FUNCTION(OnOkButtonControl)));
                        if (static_try()) {
                            if (_buttonCancel != null) {
                                // ボタンハンドラの登録
                                static_throw(_buttonCancel->RegisterHandler(
                                    SREVT_CONTROL, HANDLER_BEFORE,
                                    HANDLER_FUNCTION(OnCancelButtonControl)));
                            }
                            else {
                                static_throw(SFERR_NO_MEMORY);
                            }
                        }
                    }
                    else {
                        static_throw(SFERR_NO_MEMORY);
                    }
                }
            }
            else {
                static_throw(SFERR_NO_MEMORY);
            }
        }
    }
}

ModifyWindow に関する追加処理

ModifyWindow::ModifyWindow(SFXDateConstRef date, VCalendarFilePtr vcal)
    : DataInputWindow(date), // 親コンストラクタを呼び出す
      _vcal(vcal) // 修正するデータ
{
    SFXDate start = _vcal->GetStartDate();
    // テキストコントロールの初期値に時間を設定
    _textHour->SetText(SFXWideString::Format("%d", start.GetHour()));
    // テキストコントロールの初期値に分を設定
    _textMinute->SetText(SFXWideString::Format("%02d", start.GetMinute()));
    // テキストコントロールの初期値に内容を設定
    _textContent->SetText(_vcal->GetSummary());
    return;
}

決定ボタンのハンドラ

HANDLER_IMPLEMENT_VOIDCONTROL(DataInputWindow, OnOkButtonControl, result, control)
{
    SFXDate start(_date);
    
    // テキストコントロールから文字列を取得して数値に変換
    SInt16 hour = static_cast<SInt16>(_textHour->GetText().AsSInt32());
    if (hour < 0 || hour >= 24) { // 範囲チェック
        hour = 0;
    }
    start.SetHour(hour);

    // テキストコントロールから文字列を取得して数値に変換
    SInt16 minute = static_cast<SInt16>(_textMinute->GetText().AsSInt32());
    if (minute < 0 || minute >= 60) { // 範囲チェック
        minute = 0;
    }
    start.SetMinute(minute);
    start.SetSecond(0); //秒は0とする(仕様)

    // 内容入力テキストコントロールから文字列を取得
    // ワイド文字列を Ansi 文字列に変換
    SFXAnsiString summary(static_cast<SFXAnsiString>(
        _textContent->GetText()));

    // データ作成 (ウィンドウの種類によって異なる処理)
    MakeData(start, summary);

    // 後ろのウィンドウ (OneDayWindow) を取得
    SFRResponderPtr oneDayWindow = GetNext();

    // 自分自身と後ろのウィンドウの両方を閉じる
    Invoke(SFXEvent(SREVT_RESPONDER_TERMINATE, SRP16_TERMINATE_INVOKE, true));
    oneDayWindow->Invoke(SFXEvent(SREVT_RESPONDER_TERMINATE,
        SRP16_TERMINATE_INVOKE, true));
    return;
}

CreateWindow の MakeData 関数

Void CreateWindow::MakeData(SFXDateConstRef start, SFXAnsiStringConstRef summary)
{
    VCalendarFilePtr vcal = ::new VCalendarFile("1.0", start, start, summary);
    if (vcal != null) {
        SyncScheduler::GetVCalCollection()->Append(vcal);
    }
    return;
}

ModifyWindow の MakeData 関数

Void ModifyWindow::MakeData(SFXDateConstRef start, SFXAnsiStringConstRef summary)
{
    if (_vcal != null) {
        _vcal->Set(start, start, start ,summary); //修正する
        SyncScheduler::GetVCalCollection()->Update(_vcal);
    }
    return;
}

VCalCollection の Update 関数

Void VCalCollection::Update(VCalendarFilePtr vcalendar)
{
    _list.Remove(_list.IndexOf(vcalendar));
    Append(vcalendar);
    vcalendar->SetFlag("m");
    return;
}