パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
コア実装クラスの修正

KTxtEditの高機能化にあたりコア実装クラスを修正する。

コア実装クラス(TMyCoreImpl)を修正し、エディットコントロールをScintillaコンポーネントに変更する。そもそもTMyCoreImplはエディットコントロールをメインウィンドウ(KTxtEditFrame)から隠蔽するのが目的で、その変更はKTxtEditFrameの修正を必要としない。

プログラミング手順

  1. コア実装クラス(TMyCoreImpl)の修正
  2. リポジトリ更新とビルドテスト

コア実装クラス(TMyCoreImpl)の修正

テキストコントロールをScintillaコンポーネント(TMyScintilla)に変更する。

  • インクルードファイルに"TMyScinitilla.h"を追加する。Scintillaのメッセージ(SCI_*)を利用するので<Scintilla.h>もインクルードする。
  • エディットコントロール(textCtrl_)をwxTextCtrlからTMyScintillaに変更する。前ステップでファイル入出力クラス(TMyFileOpenSave)は修正済で、textCtrl_をそのまま渡す。
  • textCtrl_の操作は全てSendMsgメンバ関数によるメッセージ送出に書き換える。

Scintillaコンポーネントは折り返し表示オフがデフォルトなので表示幅を超える文字列は疑似改行しない。

TMyCoreImpl.cpp(修正)

...
#include "version_macro.h"
#include "TMyOptionDialog.h"
#include "TMyFileOpenSave.h"
#include "TMyScintilla.h"
#include <Scintilla.h>
class TMyCoreImpl::Impl:public TMyOptionDialog::Observer
{
private:
TMyScintilla* const textCtrl_;
TMyFileOpenSave fileOpenSave_;
bool ConfirmIfModified() const
{
return !textCtrl_->SendMsg(SCI_GETMODIFY,0,0)
||wxMessageBox(_("The current file is modified. Do you want to discard?")
,MYAPPINFO_NAME,wxICON_QUESTION|wxYES_NO|wxNO_DEFAULT|wxCENTER)==wxYES;
}
public:
Impl(wxWindow* parent)
:textCtrl_{new TMyScintilla{parent,wxID_ANY}}
,fileOpenSave_{textCtrl_}
{
Update(TMyOptionDialog::GetInstance());
}
bool New()
{
if (ConfirmIfModified())
{
textCtrl_->SendMsg(SCI_CLEARALL,0,0);
fileOpenSave_.UnnameCurrent();
}
return true;
}
bool Open()
{
if (ConfirmIfModified()&&fileOpenSave_.Open())
{
textCtrl_->SendMsg(SCI_SETSAVEPOINT,0,0);
}
return true;
}
bool Save()
{
if (fileOpenSave_.Save())
{
textCtrl_->SendMsg(SCI_SETSAVEPOINT,0,0);
}
return true;;
}
bool SaveAs()
{
if (fileOpenSave_.SaveAs())
{
textCtrl_->SendMsg(SCI_SETSAVEPOINT,0,0);
}
return true;
}
bool Undo()
{
textCtrl_->SendMsg(SCI_UNDO,0,0);
return true;
}
bool Redo()
{
textCtrl_->SendMsg(SCI_REDO,0,0);
return true;
}
bool Cut()
{
textCtrl_->SendMsg(SCI_CUT,0,0);
return true;
}
bool Copy()
{
textCtrl_->SendMsg(SCI_COPY,0,0);
return true;
}
bool Paste()
{
textCtrl_->SendMsg(SCI_PASTE,0,0);
return true;
}
bool CanUndo() const
{
return textCtrl_->SendMsg(SCI_CANUNDO,0,0);
}
bool CanRedo() const
{
return textCtrl_->SendMsg(SCI_CANREDO,0,0);
}
bool CanCut() const
{
return !textCtrl_->SendMsg(SCI_GETREADONLY,0,0)&&!textCtrl_->SendMsg(SCI_GETSELECTIONEMPTY,0,0);
}
bool CanCopy() const
{
return !textCtrl_->SendMsg(SCI_GETSELECTIONEMPTY,0,0);
}
bool CanPaste() const
{
return textCtrl_->SendMsg(SCI_CANPASTE,0,0);
}
bool CanClose() const
{
return ConfirmIfModified();
}
bool IsModified() const
{
return textCtrl_->SendMsg(SCI_GETMODIFY,0,0);
}
wxString GetTitleString() const
{
auto path=wxString{};
auto encoding=wxString{};
if (fileOpenSave_.CurrentIsUnnamed())
{
path=_("(Unnamed)");
}
else
{
auto fileOption=fileOpenSave_.GetCurrentOption();
path=fileOpenSave_.GetCurrentPath();
encoding<<" - ["<<fileOption.encoding_;
if (fileOption.byteOrderMark_) {encoding<<_("(BOM)");}
encoding<<":";
switch (fileOption.endOfLine_)
{
case TMyFileOption::EOL::CRLF:
encoding<<_("CRLF");break;
case TMyFileOption::EOL::LF:
encoding<<_("LF");break;
case TMyFileOption::EOL::CR:
encoding<<_("CR");break;
}
encoding<<"]";
}
return wxString::Format("%s%s%s - " MYAPPINFO_NAME,textCtrl_->SendMsg(SCI_GETMODIFY,0,0)?"*":"",path,encoding);
}
wxString GetStatusString() const
{
auto pos=(Sci_Position)textCtrl_->SendMsg(SCI_GETCURRENTPOS,0,0);
auto y=(Sci_Position)textCtrl_->SendMsg(SCI_LINEFROMPOSITION,pos,0);
auto x=(Sci_Position)textCtrl_->SendMsg
(SCI_COUNTCODEUNITS,(Sci_Position)textCtrl_->SendMsg(SCI_POSITIONFROMLINE,y,0),pos);
return wxString::Format("%zd:%zd",y+1,x+1);
}
void Update(const TMyOptionDialog& subject) override
{
const auto& font=subject.GetTextCtrlFont();
textCtrl_->SendMsg(SCI_STYLESETFORE,STYLE_DEFAULT,subject.GetTextCtrlForegroundColor().GetRGB());
textCtrl_->SendMsg(SCI_STYLESETBACK,STYLE_DEFAULT,subject.GetTextCtrlBackgroundColor().GetRGB());
textCtrl_->SendMsg(SCI_STYLESETFONT,STYLE_DEFAULT,(LPARAM)(const char*)font.GetFaceName().utf8_str());
textCtrl_->SendMsg(SCI_STYLESETWEIGHT,STYLE_DEFAULT
,font.GetWeight()==wxFONTWEIGHT_NORMAL?SC_WEIGHT_NORMAL
:font.GetWeight()==wxFONTWEIGHT_LIGHT?SC_WEIGHT_SEMIBOLD:SC_WEIGHT_BOLD);// Handles 3 levels of weight at max.
textCtrl_->SendMsg(SCI_STYLESETITALIC,STYLE_DEFAULT,font.GetStyle()==wxFONTSTYLE_ITALIC);
textCtrl_->SendMsg(SCI_STYLESETSIZE,STYLE_DEFAULT,font.GetPointSize());
textCtrl_->SendMsg(SCI_STYLECLEARALL,0,0);
textCtrl_->SendMsg(SCI_SETMARGINWIDTHN,0
,textCtrl_->SendMsg(SCI_TEXTWIDTH,STYLE_LINENUMBER,(LPARAM)"_999999"));
}
wxMenu* CreateRecentFilesMenu()
{
return fileOpenSave_.CreateRecentFilesMenu();
}
};
...

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

Git for Windowsリポジトリを更新する。ビルド実行して動作を確認する。旧バージョンのwxTextCtrlはやり直し操作(アンドゥ/リドゥ)が不完全だった。Scintillaコンポーネントのそれは必要十分な機能を提供するが、連続するキー入力は改行を含めて一つのアンドゥ対象とするので、あなたが慣れ親しんだエディタ(例えば秀丸)と操作性を異にするかもしれない。なおアンドゥ対象はSCI_BEGINUNDOACTION/SCI_ENDUNDOACTIONメッセージでいかようにもカスタマイズできる。

UMLクラス図

アプリケーションの構成は旧バージョンから変わらない。最主要コンポーネントをwxTextCtrlからTMyScintillaに変更し、両者のインターフェースも基底文字型も異なりながら、変更に要したコーディングは1時間強だった。