RichEditのちらつきを抑えるには?

解決


挑戦者  2004-05-28 07:36:44  No: 9213  IP: [192.*.*.*]

初めまして。早速ですが質問に入らせていただきます。
Delphi初心者ながら、チャットクライアントを作りました。
というか途上です(いつかChanpionに:もっと上を目指したいです)
ログの表示にはRichEditを使っているのですが、タグに対応させた為か
一度に複数行(二桁)表示された場合、ちらつきが非常に気になります。
現在はSelAttributesで色・フォント・サイズ・書式を変更しています。
(現実には複数行表示ではなくて、複数人同時・連続発言⇒連続表示ですが)
色々探し回ってみましたが、ちらつきはImageに関するものばかりでした。
何かいい手段がありましたら、ご教授お願いします。<(。。)>

編集    削除
ふぐちゃん  2004-05-28 07:49:27  No: 9214  IP: [192.*.*.*]

内容の更新を

  RichEdit1.Lines.BeginUpdate;
  try
    { 内容の更新 }
  finally
    RichEdit1.Lines.EndUpdate;
  end;

としても改善されませんか?

編集    削除
挑戦者  2004-05-28 09:01:46  No: 9215  IP: [192.*.*.*]

素早いレス、ありがとうございます。
BeginUpdate/EndUpdate は、すでにやっておりまして、
一旦BkColor(白にしています)で塗り潰される事による
ちらつきを抑え込みたいのです(非常に目に悪そうです)
スムーズなスクロールをさせているアプリケーションを
見掛けますが、APIを駆使しないと無理なんでしょうか…?

編集    削除
ふぐちゃん  2004-05-28 09:18:52  No: 9216  IP: [192.*.*.*]

具体的にどんな処理なのか文章だけではイメージが湧かないのですが、
とりあえずRichEditのDoubleBufferedプロパティをTrueにしてみては?
もしかしたらもう試していますか?

編集    削除
挑戦者  2004-05-28 09:23:16  No: 9217  IP: [192.*.*.*]

気付いた事が一つ。ログ表示処理のあと BeginUpdate の前に
  if RichEdit.Perform(EM_LINEFROMCHAR, -1, 0) > 100 then
    for i := 1 to 30 do RichEdit.Lines.Delete(0);
で、最大表示行数を制限しているのですが、無関係でしょうか。

編集    削除
挑戦者  2004-05-28 09:33:41  No: 9218  IP: [192.*.*.*]

駄目でした。RichEdit.DoubleBuffered := True; にすると、
何故かログの表示が真っ白になります。

編集    削除
ふぐちゃん  2004-05-28 09:45:51  No: 9219  IP: [192.*.*.*]

> 気付いた事が一つ。ログ表示処理のあと BeginUpdate の前に
>   if RichEdit.Perform(EM_LINEFROMCHAR, -1, 0) > 100 then
>     for i := 1 to 30 do RichEdit.Lines.Delete(0);
> で、最大表示行数を制限しているのですが、無関係でしょうか。
BeginUpdateの前で、ということですから、ちらつくでしょうね。

編集    削除
挑戦者  2004-05-28 10:07:55  No: 9220  IP: [192.*.*.*]

EndUpdte の間違いでした。少々長いですが、ソースを書きます。
  with (RichEdit As TRichEdit) do begin
    Lines.BeginUpdate;
    try
      Lines.Add(WORD);
      OLDPos := SelStart - Length(WORD) - 2;
      END := SelStart;
      for i := 0 to 3 do while TAGLIST[i] <> '' do begin
        TAGSTART := StrToInt(Copy(TAGLIST[i], 1, AnsiPos('*/', TAGLIST[i]) - 1));
        Delete(TAGLIST[i], 1, AnsiPos('*/', TAGLIST[i]) + 1);
        TAGPROV[i] := Copy(TAGLIST[i], 1, AnsiPos('*/', TAGLIST[i]) - 1);
        Delete(TAGLIST[i],1,AnsiPos('*/',TAGLIST[i]) + 1);
        SelStart := OLDPosition - 1 + TAGSTART;
        SelLength := END - SelStart;
        if TAGPROV[i] <> '' then case i of
          0: SelAttributes.Color := ColorType[AnsiIndexText(TAGPROV[0], ColorTAG)];
          1: SelAttributes.Size := SizeType[AnsiIndexText(TAGPROV[1], SizeTAG)];
          2: SelAttributes.Style := StyleType[AnsiIndexText(TAGPROV[2], StyleTAG)];
          3: SelAttributes.Name := TAGPROV[3];
        end;
        TAGPROV[i] := '';
      end;
      if Perform(EM_LINEFROMCHAR, -1, 0) > 150 then
        for i := 1 to 30 do Lines.Delete(0);
      SelStart := END;
    finally
      Lines.EndUpdate;
    end;
  end;

TAGLIST[i]にはタグ抽出ルーチンでタグ位置+'*/'+タグ(省略型)+'*/'を交互に入れています。
ここ(実描画ルーチン)ではタグ位置と、TAGPROV[i]にタグを1つづつ取り出して、
省略タグの配列を検索、その数字を実際の SelAttributes の配列に入れて変換しています。

編集    削除
ふぐちゃん  2004-05-28 22:00:06  No: 9221  IP: [192.*.*.*]

{ と } で処理のまとまりごとにコメント化してみて問題箇所を特定してみるのはどうですか?
原始的な方法ですが、結構効果があります。
あと、これ
http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=33#0216.txt
少しでも問題解決のヒントになりませんか?

編集    削除
挑戦者  2004-05-28 23:32:37  No: 9222  IP: [192.*.*.*]

そのHPも参考にさせて頂きましたが、最初に書いたとおり私は Delphi を触り始めて
まだ三ヶ月と日が浅く勉強不足で、APIで書かれたソースは半分も理解できません。
ちょっと質問の意味がちゃんと伝わっていなかったようなので、改めて書かせてもらいます。
RichEditに文字を高速に描画させるのではなく、連続で書き込んだ時のスクロール時の
ちらつきを消したいのです。やりたい事の簡潔なソースを書きます。

FormにRichEditとButtonを配置して、RichEditのHideSelectionをFalseに。

procedure TForm1.Button1Click(Sender: TObject);
var
i,ENDPOS:     Integer;
begin
  for i := 0 to 20 do
    with (RichEdit1 As TRichEdit) do
    begin
      Lines.BeginUpdate;
      try
        Lines.Add('Delphi Q & A 掲示板');
        ENDPOS := SelStart;
        SelStart := SelStart - 14;
        SelLength := 5;
        SelAttributes.Color := clRed;
        SelStart := ENDPOS;
      finally
      Lines.EndUpdate;
      end;
    end;
end;
ボタンを押すと文字が流れて、再描画の為に逐一塗り潰している為なのかちらつきが出ます。
このちらつきを消して、スムーズにスクロールさせたいのです。
一旦ログを貯めこんで一気に描画を。とも考えましたが、連続で次のログが来ると駄目でした。
ここでなら解決できそうに思えてこちらに書きました。
Delphi先駆者の皆様方、改めてよろしくお願いします。

編集    削除
にしの  2004-05-29 00:04:46  No: 9223  IP: [192.*.*.*]

これだと、1回のループごとにBeginUpdate, EndUpdateすることになるので、ちらつきますよね。

編集    削除
ふぐちゃん  2004-05-29 00:31:26  No: 9224  IP: [192.*.*.*]

にしのさんが書いていらっしゃる通りで、for i := 0 to 20 do のループの中で
BeginUpdate〜EndUpdate を繰り返してしまうと、BeginUpdate〜EndUpdateの意味が
全くなくなってしまいます。
それにしても、挑戦者さんの最初の質問からはこういうことは想像できませんでした。(汗)

編集    削除
ふぐちゃん  2004-05-30 03:49:21  No: 9225  IP: [192.*.*.*]

挑戦者さん、ちらつきは改善されましたか?

編集    削除
挑戦者  2004-05-30 04:00:23  No: 9226  IP: [192.*.*.*]

この方法では駄目だという事でしょうか?APIを駆使しなければ無理なのか、
又は他のコンポーネント(例えばSonEdit??)使えば解決できるのでしょうか?
チャットソフトの性格上、連続して届いたログは連続して表示したいのです。
ちなみにBeginUpdate〜EndUpdateを使わず処理すると、黒いちらつきが入るばかりか、
複数の表示色/フォント/サイズ変更等などがあると、とんでもなく遅くなったりします。

編集    削除
ふぐちゃん  2004-05-30 04:21:31  No: 9227  IP: [192.*.*.*]

> この方法では駄目だという事でしょうか?
私の最初のレスと同じことなのですが、

procedure TForm1.Button1Click(Sender: TObject);
var
  i, ENDPOS: Integer;
begin
  with RichEdit1 do
  begin
    Lines.BeginUpdate;
    try
      for i := 0 to 20 do
      begin
        { 処理 }
      end;
    finally
      Lines.EndUpdate;
    end;
  end;
end;

こういう風に書くべきではないでしょうか。
for文の内側に BeginUpdate〜EndUpdate が入っていると、
繰り返しの数だけ EndUpdate で更新されるはずです。
もし上記の方法でもちらつくようでしたら、このことは忘れてください。(苦笑)

編集    削除
挑戦者  2004-05-30 07:27:19  No: 9228  IP: [192.*.*.*]

いや、ちょっとこちらのやりたい事が伝わっていないようです(汗
チャットクライアントなので、基本的には発言を一行だけ処理します。
当然、表示は一行だけなのでちらつきはありません。(気にならないだけかも?)
ですが、複数人が同時に発言すると、ソケットが連続して受け取って
処理を回す為に一気にスクロールして、ちらつくのです。
タイミングにもよりますが、二行続いただけでも目立ちます。
わざわざループを作ってソースを書いたのは、分かり易くする為だったのですが、
かえって混乱させてしまって申し訳ありませんでした。
あと、ダミーのRichEditに一旦表示してからStream経由でコピーさせようと
試みましたが、失敗に終わりました・・・

編集    削除
ふぐちゃん  2004-05-30 07:42:16  No: 9229  IP: [192.*.*.*]

挑戦者さんの発言とコードを見て私にわかることは書いたつもりですので、
あとは他の方からのレスを期待しましょう。

編集    削除
挑戦者  2004-05-31 02:38:27  No: 9230  IP: [192.*.*.*]

ふぐちゃんさん、質問に延々お付き合い下さってありがとうございます。
不可能とは思えないので今後も自分なりに色々と調べてやってみるつもりですが、
何かいい方法がありましたら、みなさんご教授お願いします。
素人考えで的外れかもしれませんが、OS⇔アプリケーションの間のやり取り
に何か細工できるのはないかと睨んでおります。

編集    削除
にゃ〜  2004-05-31 07:01:38  No: 9231  IP: [192.*.*.*]

>チャットクライアントなので、基本的には発言を一行だけ処理します。
>当然、表示は一行だけなのでちらつきはありません。(気にならないだけかも?)
>ですが、複数人が同時に発言すると、ソケットが連続して受け取って
>処理を回す為に一気にスクロールして、ちらつくのです。

ならば発想を変えてみたらどうかにゃ〜?

◇RichEditに入れるのは実際に見える行だけ。見えない行を入れなければスクロールもなし。
◇受信文字列をTStringListなどに貯めて、表示する部分だけをTimerでRichEditに転送して、書式を変更。
◇書式の変更に時間がかかってチラツクのなら、文字列をあらかじめRTF形式に変換してからRichEditに転送。

編集    削除
LupinⅢ  URL  2004-06-01 21:04:39  No: 9232  IP: [192.*.*.*]

流れる文字でしたらTipsがここにありますが、参考にならないでしょうか?
http://www.geocities.jp/lupin_home/delphi/index.html#1に

編集    削除
挑戦者  2004-06-03 00:35:51  No: 9233  IP: [192.*.*.*]

LupinⅢさんの紹介ページのTipsは、Imageに描画させてますね。
Imageで全て作り直すとすると、私の力にはとても・・・(汗
にゃ〜さんの
> 文字列をあらかじめRTF形式に変換してからRichEditに転送
が今の私にできそうな有効な手段のようです。
とりあえず、RTF方式での転送がうまくいくかどうか頑張ってみます。

編集    削除
挑戦者  2004-06-23 00:07:10  No: 9234  IP: [192.*.*.*]

色々と試行錯誤してみて、最終的に文字列を貯めて、
尚且つバックカラーをちらつきが目立たない色にするという
消極的戦法(笑)で一応の解決を図りました。
お答えを下さったみなさん、ありがとうございました。

編集    削除