エディタの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() を実装しなさい。