パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
システムイベントハンドラの実装

KTxtEditプロジェクトにアプリケーションのアイドル時と終了時のハンドラを実装する。

アプリケーションアイドル時のハンドラを実装し、状況検知してメニュー項目のアクティブ/非アクティブを切り替え、ファイル名とテキストカーソル位置を表示するようにする。終了時のハンドラを実装し、編集有無によるダイアログ確認を加える。これでテキストエディタとしての基本機能を実装したものとする。

プログラミング手順

  1. ステータスバーの修正
  2. アプリケーションアイドル時イベントハンドラの実装
  3. アプリケーション終了時イベントハンドラの実装
  4. リポジトリ更新とビルドテスト

ステータスバーの修正

[Management]ウィンドウ[Resources]ページ(wxSmithリソースマネージャ)のツリービューで[Resources|KTxtEdit|wxFrame|KTxtEditFrame|Tools|wxStatusBar:statusBar_]ノードを選択する。下部プロパティエディタで以下に設定する。

プロパティ
Fields 2
Field 1 Width 1
Variable width チェックする
Style wxSB_NORMAL
Field 2 Width 50
Variable width チェックしない
Style wxSB_NORMAL

アプリケーションアイドル時イベントハンドラの実装

wxSmithはアプリケーションアイドル時イベント(wxEVT_IDLE)ハンドラのスケルトンを生成できないので、全てマニュアルでコーディングする。KTxtEditFrameクラスにOnIdleメンバ関数を追加し、コンストラクタでConnectメンバ関数でwxEVT_IDLEハンドラにOnIdleを定義して、OnIdleに処理を実装する。OnIdleはファイル名をメインウィンドウタイトルバーに表示し、テキストカーソル位置をステータスバーに表示する。

KTxtEditFrame.h

OnIdleはwxSmith管理外なので、必ず//(*Handlers(KTxtEditFrame) ... //*)の外に置く。

class KTxtEditFrame: public wxFrame
{
public:
...
private:
//(*Handlers(KTxtEditFrame)
...
//*)
void OnIdle(wxIdleEvent& event);
//(*Identifiers(KTxtEditFrame)
...
//*)
//(*Declarations(KTxtEditFrame)
wxStatusBar* statusBar_;
wxTextCtrl* textCtrl_;
//*)
...
};

KTxtEditFrame.cpp

wxEVT_IDLEハンドラにOnIdleを定義するConnect関数はwxSmith管理外なので、必ず//(*Initialize(KTxtEditFrame) ... //*)の外に置く。

KTxtEditFrame::KTxtEditFrame(wxWindow* parent,wxWindowID id)
{
//(*Initialize(KTxtEditFrame)
...
//*)
Connect(wxEVT_IDLE,(wxObjectEventFunction)&KTxtEditFrame::OnIdle);
...
}
...
void KTxtEditFrame::OnIdle(wxIdleEvent& event)
{
SetTitle(wxString::Format("%s%s - " MYAPPINFO_NAME
,textCtrl_->IsModified()?"*":""
,fileFullPath_.IsEmpty()?_("(Unnamed)"):fileFullPath_));
auto x=long{};auto y=long{};
textCtrl_->PositionToXY(textCtrl_->GetInsertionPoint(),&x,&y);
statusBar_->SetStatusText(wxString::Format("%d:%d",y+1,x+1),1);
GetMenuBar()->FindItem(KTxtEditFrame::idMenuSave)->Enable(textCtrl_->IsModified());
GetMenuBar()->FindItem(KTxtEditFrame::idMenuUndo)->Enable(textCtrl_->CanUndo());
GetMenuBar()->FindItem(KTxtEditFrame::idMenuRedo)->Enable(textCtrl_->CanRedo());
GetMenuBar()->FindItem(KTxtEditFrame::idMenuCut)->Enable(textCtrl_->CanCut());
GetMenuBar()->FindItem(KTxtEditFrame::idMenuCopy)->Enable(textCtrl_->CanCopy());
GetMenuBar()->FindItem(KTxtEditFrame::idMenuPaste)->Enable(textCtrl_->CanPaste());
event.Skip();
}
...

アプリケーション終了時イベントハンドラの実装

メインウィンドウのクローズイベントwxEVT_CLOSEで編集有無によるダイアログ確認する。このハンドラはwxSmithでスケルトンを生成できる。[Management]ウィンドウ[Resources]ページ(wxSmithリソースマネージャ)のツリービューで[Resources|KTxtEdit|wxFrame|KTxtEditFrame|wxFrame]ノードを選択する。下部プロパティエディタをイベントエディタに切り替え、EVT_CLOSEハンドラをOnCloseという名前で作成する。ソースコードに挿入されたスケルトンに以下を実装する。

...
void KTxtEditFrame::OnClose(wxCloseEvent& event)
{
if (event.CanVeto()&&!(!textCtrl_->IsModified()
||wxMessageBox(_("The current file is modified. Do you want to discard?")
,MYAPPINFO_NAME,wxICON_QUESTION|wxYES_NO|wxNO_DEFAULT|wxCENTER)==wxYES))
{
event.Veto();
}
else
{
event.Skip();
}
}
...

リポジトリ更新とビルドテスト

動作確認(4)を参考にGit for Windowsリポジトリを更新する。ビルド実行してファイル名とテキストカーソル位置の表示やアプリケーション終了時の挙動を確認する。

UMLクラス図

簡略したUMLクラス図でアプリケーションの構成を説明する。

  • KTxtEditFrameクラスにアイドル時イベントハンドラと終了時イベントハンドラを追加する。
覚え書き
クラス図にアクター(ここでは"システム")はルール違反だが直感的な理解として書き加えた。wxCloseEventの公開はKTxtEditFrameクラス(あるいはwxWindow基底クラス)とするのが正確と思われるが、この図は意味論(セマンティクス)を優先しシステムとする。