ホーム >プログラム >Delphi 6 ローテクTips

RichEditのタブ幅を設定

プログラムのソースコードを見るときにタブ幅を変えられないとちょっと困るのでリッチエディットのタブ幅を設定してみようというページ。
表形式のデータを桁を揃えてレイアウトするような目的ではなく、単純にテキストのタブ幅を揃えて表示させたいわけです。


参考サイト

http://www13.plala.or.jp/kmaeda/winc/rich_tab.htm
http://www13.plala.or.jp/kmaeda/winc/rich_tab.htm

Twip - Wikipedia
http://ja.wikipedia.org/wiki/Twip

EM_SETPARAFORMATメッセージ

もっとちゃんとしたやり方があるのかも知れませんが、リッチエディットのテキストを全選択してからEM_SETPARAFORMATメッセージを送る方法を取ります。

CreateWindowW APIで作成したUnicode対応のRichEditではEM_SETTABSTOPSメッセージを送ることで実現できたのですがD6のVCLのTRichEditではだめなようです。

procedure TForm1.MenuItem_Tab8Click(Sender: TObject);
var
  l_Tab: Integer;
begin
  l_Tab := TMenuItem(Sender).Tag * 4;
  SendMessage(RichEdit1.Handle, EM_SETTABSTOPS, WPARAM(1), LPARAM(@l_Tab)); //VCLのTRichEditでは変化なし
end;

RichEditには色々なバージョンがあるようでそのへんの問題なのかなぁというところです。

それではというのでEM_SETPARAFORMATメッセージを送るやり方でやってみたところ単純にメッセージを送っただけではだめなようです。
タブ幅をセットしてメッセージを送った後に入力したテキストのタブ幅はセット後のタブ幅なのですが、タブ幅をセットする以前のテキストは元のタブ幅のままでした。
表形式のデータを桁を揃えて表示させる場合等であればそれもいいのでしょうが、単純にプログラムのソースコードのタブ幅を揃えたい場合にはこれでは困ります。
ということで色々やってみた結果RichEditのテキストを全選択状態にしてからEM_SETPARAFORMATメッセージを送ることで実現できました。

procedure TForm1.MenuItem_Tab8Click(Sender: TObject);
//タブの設定
//http://www13.plala.or.jp/kmaeda/winc/rich_tab.htm
//http://ja.wikipedia.org/wiki/Twip
var
  l_MenuItem  : TMenuItem;
  li_Tab      : Integer;
  l_Param     : TParaFormat;
  li_Pos      : Integer;
  i : Integer;
begin
  l_MenuItem         := TMenuItem(Sender);
  l_MenuItem.Checked := True;

  FillChar(l_Param, SizeOf(l_Param), 0);
  l_Param.cbSize    := SizeOf(l_Param);
  l_Param.dwMask    := PFM_TABSTOPS;
  l_Param.cTabCount := High(l_Param.rgxTabs) +1;
  //TParaFormatのタブ幅は単位はtwipsなので画面表示用に計算。
  li_Tab := l_MenuItem.Tag * Abs(RichEdit1.Font.Size) * 20 div 2; //半角スペースの幅をFont.Sizeの半分とするので2で割る
  for i := 0 to High(l_Param.rgxTabs) do
  begin
    l_Param.rgxTabs[i] := li_Tab * (i+1);
  end;

  //カーソル位置を保存。
  li_Pos := RichEdit1.SelStart;

  RichEdit1.SelectAll;
  //タブ幅セット。
  SendMessage(RichEdit1.Handle, EM_SETPARAFORMAT, 0, LPARAM(@l_Param));

  //カーソル位置を復元。
  RichEdit1.SelStart := li_Pos;
end;

ファイルを読み込み

タブ幅をセットしてファイルを読み込む場合は一旦テキストをクリアしてタブ幅をセットしてから読み込まないとうまく行きません。

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (OpenDialog1.Execute) then
  begin
    try
      RichEdit1.Clear;
      MenuItem_Tab8Click(nil);
      RichEdit1.Lines.LoadFromFile(OpenDialog1.FileName);
    except
      ShowMessage(Format('%s'#13'読み込みエラー', [OpenDialog1.FileName]));
    end;
  end;
end;

procedure TForm1.MenuItem_Tab8Click(Sender: TObject);
//タブの設定
//http://www13.plala.or.jp/kmaeda/winc/rich_tab.htm
//http://ja.wikipedia.org/wiki/Twip
var
  l_MenuItem : TMenuItem;
  li_Tab     : Integer;
  l_Param    : TParaFormat;
  li_Pos     : Integer;
  i : Integer;
begin
  if not(Sender is TMenuItem) then
  begin
    l_MenuItem := nil;
    for i := 0 to MenuItem_Tab.Count -1 do
    begin
      if (MenuItem_Tab.Items[i].Checked) then
      begin
        l_MenuItem := MenuItem_Tab.Items[i];
        Break;
      end;
    end;
   if (l_MenuItem = nil) then
    begin
      Exit;
    end;
  end else
  begin
    l_MenuItem := TMenuItem(Sender);
    l_MenuItem.Checked := True;
  end;

  FillChar(l_Param, SizeOf(l_Param), 0);
  l_Param.cbSize    := SizeOf(l_Param);
  l_Param.dwMask    := PFM_TABSTOPS;
  l_Param.cTabCount := High(l_Param.rgxTabs) +1;
  //TParaFormatのタブ幅は単位はtwipsなので画面表示用に計算。
  li_Tab := l_MenuItem.Tag * Abs(RichEdit1.Font.Size) * 20 div 2; //半角スペースの幅をFont.Sizeの半分とするので2で割っている
  for i := 0 to High(l_Param.rgxTabs) do
  begin
    l_Param.rgxTabs[i] := li_Tab * (i+1);
  end;

  //カーソル位置を保存。
  li_Pos := RichEdit1.SelStart;

  RichEdit1.SelectAll;
  //タブ幅セット。
  SendMessage(RichEdit1.Handle, EM_SETPARAFORMAT, 0, LPARAM(@l_Param));

  //カーソル位置を復元。
  RichEdit1.SelStart := li_Pos;
end;

2011-11-26: