Edit Control で Text Editor を作成する



Edit Control を使ってコピーや貼り付けもできる Text Editor を作成します。
誰かが Text Editor が作れるようになったら Windows Program も一人前だと言っていましたが、 実は Text Editor を作るのは非常に簡単なのです。(^_^;

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの作成

  1. テンプレートを使って、新規プロジェクト(Edit)を作成して下さい。
    datafile.h と datafile.cpp をフォルダーに格納して [プロジェクト][既存項目の追加] からプロジェクトに追加します。
    datafile.h DATAFILE Object Class Library のヘッダーファイル
    datafile.cpp DATAFILE Object Class Library のプログラムファイル
    DATAFILE Object Class は ★Object Class Library から提供しています。
  2. ファイル関係のメニューを追加して下さい。
    ID キャプション
    IDM_NEW 新規作成(&N)
    IDM_OPEN ファイルを開く(&O)
    IDM_SAVE 上書き保存(&S)
    IDM_WRITE 名前を付けて保存(&A)
  3. Stdafx.h を表示して #include "datafile.h" を追加して下さい。
    テンプレートを使って作成したとき(プリコンパイルヘッダを使ったとき)は Stdafx.h にインクルードを追加します。
        // TODO: プログラムで必要なヘッダー参照を追加してください。
        #include "datafile.h"
        
  4. datafile.cpp の #include を修正して下さい。
    テンプレートを使って作成したときは、Stdafx.h をインクルードします。
        //#include <windows.h>
        //#include "datafile.h"
        #include "StdAfx.h"
        
  5. Edit.cpp を表示して、プログラム先頭の適当な位置に次のコードを追加して下さい。
    ID_EDIT は Edit Control の ID です。
    DataFile はファイルを入出力する Object Class です。
    hEdit は Edit Control の HANDLE です。
    szDir[] にはファイルを入力(出力)するときの規定のフォルダー名を格納します。
    szStr[] は TEXT データの入出力バッファで、編集領域はシステムが自動的に確保してくれます。
        #define     ID_EDIT 100         // エディットコントロールのID
        DATAFILE    DataFile;
    
        HWND        hEdit;              // エディットウィンドウのハンドル
        char        szDir[MAX_PATH];    // DIR の規定値
        char        szStr[100000];
        
  6. CALLBACK WndProc( ) を表示して WM_CREATE: を追加して下さい。
    rc は Window サイズを取得する RECT 構造体です。
    id には MessageBox() の戻り値を格納します。
    ファイルに保存するとき nLen に編集された Text のサイズを取得します。
    WM_CREATE: でウインドウに EDIT Control を貼り付けてます。
    EDIT Buffer はシステムが自動的に確保してくれる領域で、その最大サイズを 100,000 に設定します。
    GetPrivateProfileString( ) で規定値ファイルを入力します。
    規定値の記録ファイル(Test.ini)から、前回操作したフォルダー(InitDir)を取得して szDir に格納します。
        RECT    rc;
        int     id,nLen;
    
        switch( message ) 
        {   case WM_CREATE:
                 GetClientRect(hWnd, &rc);
                 hEdit = CreateWindow("EDIT", NULL,
                    WS_CHILD | WS_VISIBLE | ES_WANTRETURN | ES_MULTILINE |
                    ES_AUTOVSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | WS_HSCROLL,
                    0, 0, rc.right, rc.bottom,
                    hWnd, (HMENU)ID_EDIT, hInst, NULL);
                 SendMessage(hEdit, EM_SETLIMITTEXT, (WPARAM)100000, 0);
                 GetPrivateProfileString("Editor","InitDir","c:\\",szDir,MAX_PATH,"Test.ini");
                 break;
        
  7. 規定値の取得と設定はいたって簡単です。
    規定値はプライベートプロファイルに記録され Windows のフォルダーに格納されています。
    登録されている規定値を調べるコードです。
        char        szDir[MAX_PATH];    // DIR の規定値
    
        GetPrivateProfileString("Editor","InitDir","c:\\",szDir,MAX_PATH,"Test.ini");
        
    "Editor" アプリケーション名
    "InitDir" キー名
    "c:\\" 無かった場合のデフォルト文字列
    szDir 文字を格納する領域
    MAX_PATH szDir の最大文字数
    "Test.ini" プライベートプロファイル名
  8. 規定値を登録するコードです。
    規定値ファイルが無いときは、新規に作成されます。
        WritePrivateProfileString("Editor","InitDir",szFile,"Test.ini");
        
    "Editor" アプリケーション名
    "InitDir" キー名
    szFile 登録する文字列
    "Test.ini" プライベートプロファイル名
  9. このプログラムで作成した TEST.INI ファイルを調べるとその内容は次のとおりでした。
    作成したコードと比べれば一目瞭然でしょう。
    Windows のフォルダーに腐るほど沢山の .INI ファイルが作成される理由を解っていただけたでしょうか。
        [Editor]
        InitDir=C:\DATA\CPP\Editor\ww.txt
        
  10. Menu が選択されたときの処理です。
    IDM_NEW: では TEXT Buffer を空にして、編集中のファイル名を "New" にします。
    SetWindowText(hEdit,szStr) でシステムの編集領域に TEXT を格納します。
    SetWindowText(hWnd,"New") でウインドウにファイル名を表示します。
    IDM_OPEN: では szDir のフォルダー一覧を表示して、選択されたファイルからデータを入力して、 ファイル名をウインドウに表示します。
    IDM_SAVE: ではシステムの編集領域から TEXT を取得して上書き保存します。
    GetWindowTextLength(hEdit) でシステムの編集領域のサイズを取得します。
    GetWindowText(hEdit,szStr,nLen) でシステムの編集領域から TEXT を取得します。
    DataFile.WriteData() でファイルに保存します。
    IDM_WRITE: ではシステムの編集領域から TEXT を取得して、szDir のフォルダー一覧から選択された ファイルにデータを保存します。
        switch( wmId ) 
        {
           case IDM_NEW:
               strcpy_s(szStr,100000,"");
               SetWindowText(hEdit,szStr);
               SetWindowText(hWnd,"New");
               break;
           case IDM_OPEN:
               DataFile.OpenReadData(szDir,szStr,100000);
               SetWindowText(hEdit,szStr);
               SetWindowText(hWnd,DataFile.szFile);
               break;
           case IDM_SAVE:
               nLen = GetWindowTextLength(hEdit);
               GetWindowText(hEdit,szStr,nLen);
               DataFile.WriteData(DataFile.szFile,szStr,nLen);
               break;
           case IDM_WRITE:
               nLen = GetWindowTextLength(hEdit);
               GetWindowText(hEdit,szStr,nLen);
               DataFile.OpenWriteData(szDir,szStr,nLen);
               SetWindowText(hWnd,DataFile.szFile);
               break;
           case IDM_ABOUT:
               DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
               break;
           case IDM_EXIT:
               SendMessage(hWnd, WM_CLOSE, 0, 0);
               break;
           default:
               return DefWindowProc( hWnd, message, wParam, lParam );
        }
        
  11. WM_SIZE: WM_CLOSE: WM_DESTROY: を追加(変更)します。
    WM_SIZE: では Window のサイズに合わせて Edit Control のサイズを変更します。
    終了時に現在操作しているファイル名(DataFile.szFile)を InitDir に関連付けて Test.ini に記録します。
            case WM_SIZE:
                 GetClientRect(hWnd, &rc);
                 MoveWindow(hEdit,rc.left,rc.top,rc.right,rc.bottom,TRUE);
                 break;
            case WM_CLOSE:
                 id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか",
                     (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION);
                 if (id==IDYES)  DestroyWindow(hWnd);
                 break;
            case WM_DESTROY:
                 WritePrivateProfileString("Editor","InitDir",DataFile.szFile,"Test.ini");
                 PostQuitMessage(0);
                 break;
        
  12. ビルド(コンパイル)に続いて実行を行います。
    メニューから「ファイルを開く」で TEXT ファイルを入力して下さい。
    編集メニューは用意されていませんが「Ctrl+C」のコピーや「Ctrl+V」の貼り付けなど一応の機能は備えています。
    またファイルを一度「入力・出力」すると次から規定値のフォルダーが変更されることを確認して下さい。

【演習】

次のメニューを設定して下さい。
方法が解かるとプログラムは非常に簡単です。
case IDM_COPY  : SendMessage( hEdit, WM_COPY, 0, 0 ); break;
case IDM_UNDO  : SendMessage( hEdit, WM_UNDO, 0, 0 ); break;
case IDM_CUT   : SendMessage( hEdit, WM_CUT, 0, 0 ); break;
case IDM_DELETE: SendMessage( hEdit, WM_CLEAR, 0, 0 ); break;
case IDM_PASTE : SendMessage( hEdit, WM_PASTE, 0, 0 ); break;

超初心者のプログラム入門(Win32API C++)