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プロパティは変更
されます。
よろしくお願い申し上げます。
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;
表示行数が偶数の場合には当然中央に表示する事はできません
(スクロールバーを調整すればできますが)
綺麗じゃないですけど・・・
しかもこのままだと下にページスクロールする余裕がないときに正しく取得できません・・・
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;
偶数行や中途半端に表示される領域も考慮して、中央に表示します
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;
varが抜けていたので
var
E1,E2,LineCount,TextHeight,I,TopLine,P : Integer;
R : TRect;
Bitmap : TBitmap;
SI:TScrollinfo;
KHE00221さん、F.Nさん ご回答ありがとうございます。
KHE00221さんへ
最初に示されたコードでうまく、出来ました。
「偶数行や中途半端に表示される領域も考慮して、中央に表示します」
のコードでは、30000行のファイルを読み込んだときコードを実行すると
データの最終ページが表示され、こちらの環境ではでうまく表示
出来ませんでした。
F.Nさんへ
ご回答の通り、ページスクロール分のデータが下にないと
うまくいきませんでした。ページスクロール分のデータが
あると、うまくいきました。
お二人のご回答を参考にさせていただいて、中央表示をしたいと思います。
KHE00221さんへの質問ですが、
最初のコードで
TextHeight := Bitmap.Canvas.TextHeight('□')+4;
で全角の'□'を使用するには、何か特別な理由がありますか。
(全角文字なら何でもいいのでしょうか)
また、+4 は、なぜ+4なのでしょうか。
以上、2点につき質問をさせていただきます。
よろしくお願い申し上げます。
>で全角の'□'を使用するには、何か特別な理由がありますか。
Height なので特に理由はありません
>また、+4 は、なぜ+4なのでしょうか。
2行表示しても その2行の間には隙間ができると思いますが、
この隙間を4としているだけです
何故と言われると4で合うので4としているだけです
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系:「ちょうど、豆腐の腐ったような…」
マイナス値になると最終行に移動するぽいので
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;
ご返事遅くなり、申し訳ありません。
ご回答、ありがとうございました。
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しないと取得できない感じです。
お二人のコードを参考にして、やりたいと思います。
これで、解決とさせていただきます。
ツイート | ![]() |