C++Builder Tips - メモコンポーネントとメッセージ

概要: Memo コンポーネントはウインドウクラスの "EDIT" を使っていますが、すべてのメッセージをカバーしているわけではありません。Memo コンポーネントがサポートしていない主要なメッセージについて紹介します。

Memoコンポーネントは、複数行にわたって文字列を編集できる基本的なコンポーネントです。

これは、Windowsが提供するウインドウクラス"EDIT"を使って実現されています。Memoコンポーネントは、"EDIT"クラスがメッセージによって提供している機能の多くをメソッドやプロパティとして利用できるようにしています。しかし、あまり使われない一部のメッセージには対応するプロパティやメソッドがありません。

以下に、Memoコンポーネントでサポートされない主なメッセージとその使用例を示します。

なお、コンポーネントにメッセージを送出するためにはPerformメソッドが使えます。

Performの第1引数にはメッセージ、第2引数にはWParam(int型)、第3引数にはLParam(int型)を渡します。WParamとLParamは、メッセージごとに役割が違います。これらの引数は、使われない場合には0を渡します。

    EM_GETRECT、EM_SETRECT、EM_SETRECTNP

Memoコンポーネントの中で編集領域として使う領域を取得、設定します。PerformのLParamには、指定する範囲をあらわすRECT型変数のアドレスを渡します。たとえば、次のプログラムは、Memo1コンポーネントの編集領域をMemo1全体から10ドット内側にします。EM_SETRECTNPは、メモコンポーネントの内容を再描画しない点を除き、EM_SETRECTと同じです。

    RECT R := Memo1->ClientRect;
    InflateRect(&R, -10, -10);
    Memo1->Perform(EM_SETRECT, 0, (int)&R);

次のプログラムは、Memo1コンポーネントに実際に表示されている行数を計算します。

    RECT R;
    Memo1->Perform(EM_GETRECT, 0, (int)&R);
    int N = (R.bottom - R.top) / Canvas->TextHeight("H");

    EM_SCROLL

Memoコンポーネントの内容を上下にスクロールさせるメッセージです。WParamによって4種類のスクロール方法を指定できます。

SB_LINEDOWN

1行下が見えるようにスクロールします。

SB_LINEUP

1行上が見えるようにスクロールします。

SB_PAGEDOWN

1ページ下が見えるようにスクロールします。

SB_PAGEUP

1ページ上が見えるようにスクロールします。

次のプログラムは、Memo1の内容を1行下が見えるように(全体を1行上に)スクロールします。

    Memo1->Perform(EM_SCROLL, SB_LINEDOWN, 0);

    EM_LINESCROLL

Memoコンポーネントの内容を上下左右にスクロールさせるメッセージです。WParamには水平方向の文字数を、LParamには垂直方向の行数を渡します。スクロールさせる意味がない場合は無効です。たとえば、WordWrapプロパティがtrueのときは水平スクロールはできません。

次のプログラムは、Memo1の内容を2文字と2行文左上にスクロールします。

    Memo1->Perform(EM_LINESCROLL, 2, 2);

    EM_CANUNDO、EM_UNDO、EM_EMPTYUNDOBUFFER

編集操作を取り消すためのメッセージです。Memoコンポーネント上でCtrl-Zを押したり、今テキストメニューで[元に戻す(U)]を実行するのと同じ処理を、プログラムから実行できます。

EM_CANUNDOは、元に戻す編集操作があるかどうかを判断するためのものです。たとえば、EM_CANUNDOの結果がfalseであれば、[元に戻す(U)]という操作を禁止しておくことができます。また、EM_EMPTYUNDOBUFFERは元に戻す操作のためのバッファをクリアします。

EM_EMPTYUNDOBUFFERメッセージを送出した後は、EM_CANUNDOはfalseを返します。

これらのメッセージは、いずれもWParam、LParamを使いません。

    EM_LINEFROMCHAR

指定した文字位置のある行を返します。文字の位置や行番号は、それぞれ0が開始点になります。つまり、先頭の文字や先頭の行は0であらわされます。文字位置はWParamに渡しますが、-1を渡すと現在のカーソル位置の行番号を返します。次のプログラムは、Memo1のOnKeyUpイベントを使って、キー入力があるたびに現在の行番号をキャプションに表示します。

    void __fastcall TForm1::Memo1KeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
        Caption = IntToStr(Memo1->Perform(EM_LINEFROMCHAR, -1, 0) + 1);
    }

    EM_SETTABSTOPS

タブストップの位置を指定するメッセージです。WParamには、指定するタブストップ配列の要素数を、LParamはタブストップ配列へのアドレスを渡します。ただし、WParamの値によってLParamの評価方法が変わります。

WParamが0の場合、LParamに関わらずタブストップの位置は8文字単位になります。 WParamが1の場合、LParamが指す配列は1個の要素だけを持ちますが、タブストップはここに指定された位置が連続的に繰り返されます。

WParamが2以上の場合、LParamが指す配列はWParam個の要素を持ち、この範囲を超えた部分はデフォルトのタブストップ位置になります。

タブストップは、DWord型の配列として定義し、位置はダイアログ単位であらわされます。ダイアログ単位は、文字幅の平均値の4分の1になるため、4文字単位のタブストップを定義したい場合には16を指定します。

次のプログラムは、Memo1コンポーネントのタブストップを2文字単位にします。

    DWORD TabStops[1] = { 4 * 2 };
    Memo1->Perform(EM_SETTABSTOPS, 1, (int)TabStops);

    EM_FIRSTVISIBLELINE

Memoコンポーネント上で、実際に目にみえている最初の行の行番号を返します(最初の行は0)。

    EM_GETMARGINS、EM_SETMARGINS

Memoコンポーネント上で左右のマージン(余白)を設定します。WParamは設定するマージンの種類をあらわし、LParamはMAKELONGと併用してマージンの大きさをあらわします。次のプログラムは、左側に20ドット、右側に30ドットのマージンを設定します。

    Memo1->Perform(EM_SETMARGINS,
                   EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(20, 30));

    EM_POSFROMCHAR、EM_CHARFROMPOS

Memoコンポーネント上の座標と文字の位置を相互に変換するためのメッセージです。EM_POSFROMCHARは、指定した文字位置(テキストの先頭からのバイト数)の文字の左上の座標を返します。WParamには、TPoint型の変数へのアドレスを渡します。

EM_CHARFROMPOSでは、クライアント領域の座標からその場所にある文字の位置(テキストの先頭からの位置)と行番号を返します。

次のプログラムは、Memo1のOnMouseMoveイベントを使って、マウスカーソル上にある文字の位置と行番号をキャプションに表示するものです。

    void __fastcall TForm1::Memo1MouseMove(TObject *Sender, TShiftState Shift,
          int X, int Y)
    {
        DWORD DW = Memo1->Perform(EM_CHARFROMPOS, 0, MAKELONG(X, Y));
        Caption = IntToStr(LOWORD(DW)) + ":" + IntToStr(HIWORD(DW));
    }