RichEditで指定行を中央に表示するには

解決


SH  2008-01-04 03:00:32  No: 29152

RichEditについて質問させていただきます。
テキストファイルを読み込み、RichEditに表示します。
(1000行のテキストファイル)
RichEditの表示行数が20行とします。
このとき、例えば50行目を中心とし、上下約10行ずつ
表示するには、どのようにすればよでしょうか。

XXX         ←RichEditの先頭(全体の40行目)   
・・・
・・・
・・・
50行目      ←50行目
・・・
・・・
・・・
YYY         ←RichEditの後尾(全体の60行目)

RichEdiitの先頭行は
RichEdit1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
で取得できることはわかりました。
指定行を中央に表示させるためには、後尾の行を取得するか
現在のRichEditの表示可能行数を取得しなければならないと思います。
PlainTextプロパティはtrueで実行時に不変、Fontプロパティは変更
されます。
よろしくお願い申し上げます。


KHE00221  URL  2008-01-04 22:18:04  No: 29153

procedure TForm3.Button2Click(Sender: TObject);
var
    TextHeight,TopLine,LineCount : Integer;
    R : TRect;
    Bitmap : TBitmap;
begin
    //テキストのサイズを取得
    Bitmap := TBitmap.Create;
    Bitmap.Canvas.Font.Assign(RichEdit1.Font);
    TextHeight := Bitmap.Canvas.TextHeight('□')+4;
    Bitmap.Free;

    //画面のサイズを取得
    SendMessage(RichEdit1.Handle,EM_GETRECT,0,DWORD(@R));

    //表示される行数を取得
    LineCount := (R.Bottom - R.Top) div TextHeight;

    //中央に移動
    TopLine := SendMessage(RichEdit1.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
    SendMessage(RichEdit1.Handle, EM_LINESCROLL, 0, ((50 - LineCount div 2) - TopLine)-1);

end;

表示行数が偶数の場合には当然中央に表示する事はできません
(スクロールバーを調整すればできますが)


F.N  2008-01-04 22:51:34  No: 29154

綺麗じゃないですけど・・・
しかもこのままだと下にページスクロールする余裕がないときに正しく取得できません・・・

procedure TForm1.RichEdit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  i1, i2: integer;
begin
  if Key=VK_F1 then begin
    i1 := RichEdit1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
    RichEdit1.Perform(WM_SETREDRAW, wParam(FALSE), 0);
    RichEdit1.Perform(EM_SCROLL, SB_PAGEDOWN, 0);
    i2 := RichEdit1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
    RichEdit1.Perform(EM_SCROLL, SB_PAGEUP, 0);
    RichEdit1.Perform(WM_SETREDRAW, wParam(TRUE), 0);
    ShowMessage('表示行数='+IntToStr(i2-i1+1));
  end;
end;


KHE00221  URL  2008-01-05 01:11:58  No: 29155

偶数行や中途半端に表示される領域も考慮して、中央に表示します

procedure TForm3.Button1Click(Sender: TObject);
begin
    //テキストのサイズを取得
    Bitmap := TBitmap.Create;
    Bitmap.Canvas.Font.Assign(RichEdit1.Font);
    TextHeight := Bitmap.Canvas.TextHeight('□')+4;
    Bitmap.Free;

    //画面のサイズを取得
    SendMessage(RichEdit1.Handle,EM_GETRECT,0,DWORD(@R));

    //表示される行数を取得
    LineCount := (R.Bottom - R.Top) div TextHeight;

    //中央に移動
    TopLine := SendMessage(RichEdit1.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
    SendMessage(RichEdit1.Handle, EM_LINESCROLL, 0, ((11 - LineCount div 2) - TopLine)-1);
    TopLine := SendMessage(RichEdit1.Handle, EM_GETFIRSTVISIBLELINE, 0, 0);
    SendMessage(RichEdit1.Handle, EM_LINESCROLL, 0, ((11 - LineCount div 2) - TopLine)-1);

    //ScrollBarの位置を取得
    SI.cbSize := SizeOf(TScrollinfo);
    SI.fMask := SIF_POS;
    GetScrollInfo(RichEdit1.Handle,SB_VERT,SI);
    P := SI.nPos;

    E1 := abs((LineCount mod 2)-1) * TextHeight; //偶数の場合の対処
    E2 := (R.Bottom - R.Top) mod TextHeight;     //表示しれきれない領域の対処

    SendMessage(RichEdit1.Handle, WM_VSCROLL,MakeWParam(SB_THUMBPOSITION,P+(E1 div 2)-(E2 div 2)),0);
    SendMessage(RichEdit1.Handle, WM_VSCROLL,SB_ENDSCROLL,0);

end;


KHE00221  2008-01-05 03:05:40  No: 29156

varが抜けていたので

var
  E1,E2,LineCount,TextHeight,I,TopLine,P : Integer;
  R : TRect;
  Bitmap : TBitmap;
  SI:TScrollinfo;


SH  2008-01-07 00:04:47  No: 29157

KHE00221さん、F.Nさん  ご回答ありがとうございます。

KHE00221さんへ
  最初に示されたコードでうまく、出来ました。
  「偶数行や中途半端に表示される領域も考慮して、中央に表示します」
  のコードでは、30000行のファイルを読み込んだときコードを実行すると
  データの最終ページが表示され、こちらの環境ではでうまく表示
  出来ませんでした。
F.Nさんへ
  ご回答の通り、ページスクロール分のデータが下にないと
  うまくいきませんでした。ページスクロール分のデータが
  あると、うまくいきました。

お二人のご回答を参考にさせていただいて、中央表示をしたいと思います。

KHE00221さんへの質問ですが、
最初のコードで
  TextHeight := Bitmap.Canvas.TextHeight('□')+4;
  で全角の'□'を使用するには、何か特別な理由がありますか。
  (全角文字なら何でもいいのでしょうか)
  また、+4  は、なぜ+4なのでしょうか。
以上、2点につき質問をさせていただきます。
よろしくお願い申し上げます。


KHE00221  2008-01-07 02:22:19  No: 29158

>で全角の'□'を使用するには、何か特別な理由がありますか。

Height なので特に理由はありません

>また、+4  は、なぜ+4なのでしょうか。

2行表示しても  その2行の間には隙間ができると思いますが、

この隙間を4としているだけです

何故と言われると4で合うので4としているだけです


ちりとてちん  2008-01-07 07:44:37  No: 29159

9X系:「お前の RichEdit、行の間に隙間あるな、なんでや」
NT系:「ん?、お前の RichEdit、開いとらんの?」
9X系:「行間きっちり、詰まっとるで」
NT系:「エエなぁ、俺ンも行間詰めたいんや、どないかして詰まらんかいな」
9X系:「そら贅沢ちゅうもんや、けど、出けるんやで、俺ンは開けとうても開けられへんのや」
NT系:「そうなん? ほな、詰め方、知っとったら教えてんか?」
9X系:「タダっちゅうわけいかんでぇ」
NT系:「うまいもん、おごったる、師匠からの貰いもんで、ごっつうまいもんや」
9X系:「ほンなら、教えたるで、こないするンや」

procedure TForm1.Button1Click(Sender: TObject);
var
  ParaFormat: TParaFormat2;
  LineSpacingValue, LineHeight: Integer;
begin
  //行間を変更
  LineHeight := 14; // フォントサイズ9なら、14で行間なし
  LineSpacingValue := Round(LineHeight / Screen.PixelsPerInch * 1440);
  with RichEdit1 do begin
   SelectAll;
   ParaFormat.cbSize := SizeOf(TParaFormat2);
   ParaFormat.dwMask := PFM_LINESPACING;
   ParaFormat.dyLineSpacing := LineSpacingValue;
   ParaFormat.bLineSpacingRule := 4;
   SendMessage(Handle, EM_SETPARAFORMAT, 0, LParam(@ParaFormat));
   SelStart := 0;
   SelLength := 0;
  end;
end;

NT系:「おぉ、俺のRichEdit、行間詰まっとるやないかぁ」
9X系:「ほな、おごってや、…んで、うまいもんちゅうンはナンやねん」
NT系:「これや、"ちりとてちん"、 においは変やけど、ごっつうまいモンやて、師匠言うとったで」
9X系:「ほな、ひとくちでいこか…、…うっぷ、こらナンやねん、ちぃともうまいことあらへん」
NT系:「そうなん? 俺まだ食うとらんのや、どない味や」
9X系:「ちょうど、豆腐の腐ったような…」


KHE00221  2008-01-07 18:13:31  No: 29160

マイナス値になると最終行に移動するぽいので

if P+(E1 div 2)-(E2 div 2) > 0 then 
begin
  SendMessage(RichEdit1.Handle, WM_VSCROLL,MakeWParam(SB_THUMBPOSITION,P+(E1 div 2)-(E2 div 2)),0);
  SendMessage(RichEdit1.Handle, WM_VSCROLL,SB_ENDSCROLL,0);
end;


SH  2008-01-12 23:28:20  No: 29161

ご返事遅くなり、申し訳ありません。
ご回答、ありがとうございました。

KHE00221さん。
全角の'□'と+4の件は了解しました。+4でうまくいっています。
また
if P+(E1 div 2)-(E2 div 2) > 0 then 
begin
  SendMessage(RichEdit1.Handle, WM_VSCROLL,MakeWParam(SB_THUMBPOSITION,P+(E1 div 2)-(E2 div 2)),0);
  SendMessage(RichEdit1.Handle, WM_VSCROLL,SB_ENDSCROLL,0);
end;
でOKでした。

ちりとてちんさん。

TParaFormat2は全く知りませんでした。
教えていただいたコードで、行間を狭くすること(広くすることも)
できました。
ちなみに、RichEditのフォントサイズを9にして
EM_GETPARAFORMAT(取得)もやってみました。
結果は、ParaFormat.dyLineSpacing とParaFormat.bLineSpacingRule 
がともに0となり、行間は取得できませんでした。
一度、EM_SETPARAFORMATしないと取得できない感じです。

お二人のコードを参考にして、やりたいと思います。
これで、解決とさせていただきます。


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

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






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