TRichEdit で、キャレットを行末に置くにはどうすればいいでしょう?

解決


タオタオ  2010-07-27 11:29:29  No: 38860

マウス・クリックではちゃんと行末にキャレットを置けるのですが、
それを制御で置こうとしています。
キャレットが次行の先頭に回り込んでしまうと、行番号の管理が煩雑になりそうで困っています。
一応、CRLF の手前では、思ったようにちゃんとキャレットが行末に表示されます。

どこかが悪いのか、あるいは何かが不足しているのか、どなたか解決策をご教示ください。

環境: Win98SE + Delphi4

////////////////////////////////////////////
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

// 指定の行番号の行頭にキャレットを移動させる
procedure GoCaret(Control: TRichEdit; LineNum: LongInt);
begin
  Control.SelStart := SendMessage(Control.Handle, EM_LineIndex, LineNum, 0);
end;

//  キャレット位置を Lines[Index] 文字列の最後/行末にセットする。
//  ** WordWrap された文字列の行末指定では次行の頭に行ってしまう!!。
procedure GoLineEnd(Control: TRichEdit; LineNum: LongInt);
begin
  GoCaret(Control, LineNum);
  Control.SelStart := Control.SelStart + Length(Control.Lines[LineNum]);
end;

/////////////////////////////////////////////////////////////////////////

procedure TForm1.Button1Click(Sender: TObject);
begin
  RichEdit1.Clear;
  RichEdit1.WordWrap := True;
  RichEdit1.Width := 185;
  RichEdit1.Font.Size := 9;
  RichEdit1.Lines.Add('123456789+123456789-123456789*123456789#');
  RichEdit1.Lines.Add('123456789+123456789-123456789*123456789#');
  RichEdit1.Lines.Add('123456789+123456789-123456789*123456789#');
  RichEdit1.Lines.Add('123456789+123456789-123456789*123456789#');

  GoLineEnd(RichEdit1, 0);  // 行指定が 0,2,4 だと、次行の行頭にキャレットが来てしまう。

  RichEdit1.SetFocus;
end;

end.


tor  2010-07-27 18:57:19  No: 38861

行が折り返されている場合、行の末尾と次の行の先頭は論理的に同じ位置なので文字位置では区別できません。

たとえば行が折り返されて次のように2行になっているとします。
0 1 2 3 4
5 6 7 8 9
この時、1行目の末尾と2行目の先頭はどちらも「4と5の間」という同じ状態で、見た目が違うだけです。
たいていのエディタや文書編集ソフトでは、単にカーソルを移動するだけでは「4」の後ろにキャレットを置くことはできないはずです。
(3と4の間にキャレットがある状態で右に動くと、5の前に移動する)
4の後ろにキャレットを置くには、直接その場所をクリックするか、Endキーを押すしかありません。

というわけで、考えられる手段は次のいずれかになります。
・Endキーを送りつける
・あきらめて末尾の文字の手前に移動する
(末尾の1文字を選択→切り取り→貼り付けという強引な方法もありますが、TRichEditでは効かないようです)


タオタオ  2010-07-27 22:27:26  No: 38862

tor さん、ヒントありがとうございました。

> どちらも「4と5の間」という同じ状態で、見た目が違うだけです。

Text と言う意味ではそうなんですが、行と言う意味では「違う」ので悩んでました。
このまま使うと、行が一つずれるとか、ループなどで積算されて、どんどん
行がずれるとか、バグの温床になりそうな気がして・・・。

>・Endキーを送りつける

なるほど・・です。これでできました。

>・あきらめて末尾の文字の手前に移動する

笑。。これも一度テスト・コードでやってみました。。でもなぁ・・な感じで。。

>(末尾の1文字を選択→切り取り→貼り付けという強引な方法もありますが、TRichEditでは効かないようです)

TMemo とかではどうなのでしょうね・・。今回、上手く行ったので、またテストしてみようかと・・・。

これで解決です。ありがとうございました。

procedure GoLineEnd(Control: TRichEdit; LineNum: LongInt);
begin
  GoCaret(Control, LineNum);
  SendMessage(Control.Handle, WM_KEYDOWN, VK_END, 0);
end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加