エディタのGUI化
■ GUI
今日では一般的なアプリケーションのほとんどはGUI化されてしまった。CUIに比べGUIは初期学習コストが低く初心者向けであるが、エキスパートにとっては非効率である場合もある。そしてなによりプログラムの作成工数が大幅に増加する。とは言っても、非GUIなエディタではユーザを獲得できそうもないので、エディタをGUI化する方法について述べないわけにはいかない。
メジャーなGUI環境としては、MS-Windows, Mac OS, X-Window などがある。通常、それぞれの環境でGUIのための実装方法は異なる。本稿では、MS-Windows 環境下で VC++6.0 を使い、MFC を利用し、ファイルオープン、表示が可能なエディタ(ビューワと呼んだ方がいいかも知れない)の実装方法を示す。MFC は Microsoft Foundation Class ライブラリの略で、Windows API の軽いラッパークラス、アプリケーション、ウィンドウなどを抽象化したクラス、文字列などのユーティリティクラス群を含むクラスライブラリである。必ずしも出来がいいとは言えないが、(プロによる)多くのアプリケーション開発で利用されているデファクトスタンダード的なものである。
■ AppWizard によるプログラム作成
VC++ で AppWizard を利用し、プログラムのスケルトン(骨子)を作成する。
MFC AppWizrad (exe)、
プロジェクト名は ge とする
MDI を選ぶ
■ エディットエンジンの組み込み
CEditEngine クラスの宣言、実装ファイルを作成し、プロジェクトに加える。
CDocument の派生クラスのメンバ変数に CEditEngine m_ee; を加える。
CGeDoc::OnNewDocument() で、m_ee の初期化を行う。
## column
BOOL CGeDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
m_ee.removeAll(); // エディットバッファをクリア
return TRUE;
}
## endcolumn
■ ファイルオープン
一般的な形式のファイルを取り扱うのだから、シリアライズは使用しない。
クラスウィザードで CGeDoc::OnOpenDocument() をオーバライドする。以下のようなコードが自動生成される。
## column
BOOL CGeDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
.....
return TRUE;
}
## endcolumn
lpszPathName にはオープンするファイルのフルパス名が入っているので、その名前のファイルを読み込み、エディットバッファに格納すればよい。
ファイルの読み込みには、(1) 古典的な fopen(), fgets() 系統の関数群、(2) iostream クラス、(3) MFC のファイル操作クラス、のそれぞれを使用する3種類の方法がある。他のプラットフォームへの移植性を考えれば MFC のファイルクラスは使用しない方がいいかもしれない。
ここでは、古典的なファイルI/O関数を使用してみることにする。
## column
BOOL CGeDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
FILE *fp = fopen(lpszPathName, "r");
if( !fp )
return FALSE;
char buf[4096];
while( fgets(buf, sizeof(buf), fp) != NULL )
m_ee.addText(buf);
fclose(fp);
return TRUE;
}
## endcolumn
これで、ファイルオープンダイアログによるファイルオープンが可能になる。
オープンしたファイル情報はMFCが勝手に保存してくれる。[ファイル] メニューの最近のファイルも自動的に更新される(MFC さんに感謝)。
■ テキスト表示
テキストは CView の派生クラス CGeView の OnDraw() で描画しなくてはいけない。
とりあえず以下のようなコードを書けば、エディットバッファの内容を画面に表示できる。
実行画面を ここ に置く。
## column
#define VW_LINE_HEIGHT 20
void CGeView::OnDraw(CDC* pDC)
{
CGeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CEditEngine *ee = pDoc->getEditEngine();
int py = 0;
for(int line=0; linegetLineCount(); ++line, py += VW_LINE_HEIGHT) {
CString text;
if( !ee->getText(line, text) )
break;
pDC->TextOut(0, py, text);
}
}
## endcolumn
■ まとめ
エディットエンジンを AppWizard で生成されたスケルトンに組み込むことで、簡単なテキストビューワがとりあえず実装できることを示した。
しかし、ここに示したコードでは、フォントサイズが固定になっている、背景色が白で無い場合に文字背景色とビュー背景色が異なり見苦しい、改行コードが■で表示され見苦しい、タブが■で表示され見苦しい、スクロールしない、フレームウィンドウをリサイズしたときに画面がちらつく、などの問題がある。次以降のドキュメントでそれらの解決方法を提示していく。
■ 演習問題
[1] 本稿で示した CGeDoc::OnOpenDocument() の実装では行バッファのサイズを 4096 としているが、オープンするファイルに含まれる行の行長が 4096 より大きい場合でも大丈夫か?もし問題があれば、問題が無いように書き換えなさい。
[2] iostream, MFC の CStdioFile それぞれを用いて、CGeDoc::OnOpenDocument() を実装しなさい。