6

Delphi 2009 で書式設定されたログを表示する必要があります。書式設定では、たとえば html のすべての機能を実装する必要はありませんが、色、フォント スタイルなどの小さなサブセットを実装する必要があります。

現在、TRichEdit と独自の独自タグを使用しています。たとえば、これは青色です。RTF テキストに直接アクセスできないため、これを TRichEdit で機能させるのはかなり複雑です。たとえば、テキストを青色にするには、次のようにする必要があります。

  1. 追加されたテキストを解析してタグを抽出し、どのテキストをどのようにフォーマットする必要があるかを判断します。
  2. テキストを選択します。
  3. フォーマットを適用します。
  4. テキストの選択を解除し、次の追加の準備ができているテキストの末尾に選択を移動します。

これはすべてハッキーで遅いです。TRichEdit またはジョブにより適した別のコントロールを使用してこれを行うためのより良い (より高速な) 方法を知っていますか?

TWebBrowser で HTML を使用することを検討したことを言及しておく必要があります。このアプローチの問題点は、ログの長さが 1 ~ 100000 行になる可能性があることです。通常の HTML ビューアを使用する場合、単純にテキストを追加するのではなく、毎回テキスト全体を設定する必要があります。

さらに、ログに行を追加すると、リアルタイムでログを更新する必要があります。単にファイルから読み取って一度表示するだけではありません。

4

6 に答える 6

9

簡単な解決策: カスタム描画メソッドで TListBox を使用し、書式設定ではなく基本情報のみを含むオブジェクトを使用して、ログ エントリを TObjectList に配置します (これはプレゼンテーション コードで適用されます)。

または、Virtual String List / VirtualTreeViewコンポーネントを使用します。表示する必要があるアイテムのみがレンダリングされるため、リソースが節約されます。

于 2009-06-13T09:42:20.403 に答える
4

ログの長さが 1,000,000 行であると仮定すると、HTML または RTF を使用することを忘れることができます。

Style := lbVirtualOwnerDraw;
OnDrawItem := ListDrawItem; // your own function (example in help file)
  1. アプリケーションの残りの部分に役立つ形式でデータ配列を定義します。私は単純な LogObject を使用します。
  2. すべての LogObjects を ObjectList に格納し、リストに変更 (追加、削除) があるたびに、TListBox.Count を調整して新しい ObjectList カウントに一致させます。
  3. ListDrawItem を自分で定義してインデックスを取得すると、ObjectList (データベースなど) から情報を取得し、オンデマンドで解析できます。

一度に少数のエントリしか表示しないため、ロード時に 100 万行すべてを解析しようとする際の「速度低下」がないため、「オンデマンド解析」アプローチの方がはるかに優れています。

あなたの実際の問題を知らなくても、私の経験では、これは一度習得して習得したテクニックであり、ほとんどのデータ指向アプリケーションで役立つと言えます。

機能強化には、リスト ボックスの上にヘッダー コントロールを追加すること (私はそれらをパネルにまとめています) が含まれており、優れた TListView コントロールを作成できます。ヘッダー コントロールのクリック イベントに並べ替えロジックを少し追加すると、オブジェクト リストを並べ替えることができます。あとは、ListBox.Invalidate を呼び出してビューを更新するだけです (可能な場合)。

++ リアルタイム更新用。現時点では、リストボックスを1秒間に1000回更新したくないので、タイマーイベントをトリガーしてListBox.Countを調整します.. :-)

于 2009-06-13T10:09:49.387 に答える
2

提案どおりに TListbox を使用する場合は、ユーザーが表示している行の詳細をクリップボードにコピーできるようにしてください。ログから行をコピーできないことほど悪いことはありません。

于 2009-06-14T06:44:35.237 に答える
1

興味のある方のために、これが私が最終的に使用したコードです。これをTVirtualStringTreeのOnAfterCellPaintイベントにアタッチすると、目的の結果が得られます。

(*
  DrawHTML - Draws text on a canvas using tags based on a simple subset of HTML/CSS

  <B> - Bold e.g. <B>This is bold</B>
  <I> - Italic e.g. <I>This is italic</I>
  <U> - Underline e.g. <U>This is underlined</U>
  <font-color=x> Font colour e.g.
                <font-color=clRed>Delphi red</font-color>
                <font-color=#FFFFFF>Web white</font-color>
                <font-color=$000000>Hex black</font-color>
  <font-size=x> Font size e.g. <font-size=30>This is some big text</font-size>
  <font-family> Font family e.g. <font-family=Arial>This is arial</font-family>
*)
procedure TfrmSNMPMIBBrowser.DrawHTML(const ARect: TRect; const ACanvas: TCanvas; const Text: String);

  function CloseTag(const ATag: String): String;
  begin
    Result := concat('/', ATag);
  end;

  function GetTagValue(const ATag: String): String;
  var
    p: Integer;
  begin
    p := pos('=', ATag);

    if p = 0 then
      Result := ''
    else
      Result := copy(ATag, p + 1, MaxInt);
  end;

  function ColorCodeToColor(const Value: String): TColor;
  var
    HexValue: String;
  begin
    Result := 0;

    if Value <> '' then
    begin
      if (length(Value) >= 2) and (copy(Uppercase(Value), 1, 2) = 'CL') then
      begin
        // Delphi colour
        Result := StringToColor(Value);
      end else
      if Value[1] = '#' then
      begin
        // Web colour
        HexValue := copy(Value, 2, 6);

        Result := RGB(StrToInt('$'+Copy(HexValue, 1, 2)),
                      StrToInt('$'+Copy(HexValue, 3, 2)),
                      StrToInt('$'+Copy(HexValue, 5, 2)));
      end
      else
        // Hex or decimal colour
        Result := StrToIntDef(Value, 0);
    end;
  end;

const
  TagBold = 'B';
  TagItalic = 'I';
  TagUnderline = 'U';
  TagBreak = 'BR';
  TagFontSize = 'FONT-SIZE';
  TagFontFamily = 'FONT-FAMILY';
  TagFontColour = 'FONT-COLOR';

var
  x, y, idx, CharWidth, MaxCharHeight: Integer;
  CurrChar: Char;
  Tag, TagValue: String;
  PreviousFontColor: TColor;
  PreviousFontFamily: String;
  PreviousFontSize: Integer;

begin
  // Start - required if used with TVirtualStringTree
  ACanvas.Font.Size := Canvas.Font.Size;
  ACanvas.Font.Name := Canvas.Font.Name;
  ACanvas.Font.Color := Canvas.Font.Color;
  ACanvas.Font.Style := Canvas.Font.Style;
  // End

  PreviousFontColor := ACanvas.Font.Color;
  PreviousFontFamily := ACanvas.Font.Name;
  PreviousFontSize := ACanvas.Font.Size;

  x := ARect.Left;
  y := ARect.Top;
  idx := 1;

  MaxCharHeight := ACanvas.TextHeight('Ag');

  While idx <= length(Text) do
  begin
    CurrChar := Text[idx];

    // Is this a tag?
    if CurrChar = '<' then
    begin
      Tag := '';

      inc(idx);

      // Find the end of then tag
      while (Text[idx] <> '>') and (idx <= length(Text)) do
      begin
        Tag := concat(Tag,  UpperCase(Text[idx]));

        inc(idx);
      end;

      ///////////////////////////////////////////////////
      // Simple tags
      ///////////////////////////////////////////////////
      if Tag = TagBold then
        ACanvas.Font.Style := ACanvas.Font.Style + [fsBold] else

      if Tag = TagItalic then
        ACanvas.Font.Style := ACanvas.Font.Style + [fsItalic] else

      if Tag = TagUnderline then
        ACanvas.Font.Style := ACanvas.Font.Style + [fsUnderline] else

      if Tag = TagBreak then
      begin
        x := ARect.Left;

        inc(y, MaxCharHeight);
      end else

      ///////////////////////////////////////////////////
      // Closing tags
      ///////////////////////////////////////////////////
      if Tag = CloseTag(TagBold) then
        ACanvas.Font.Style := ACanvas.Font.Style - [fsBold] else

      if Tag = CloseTag(TagItalic) then
        ACanvas.Font.Style := ACanvas.Font.Style - [fsItalic] else

      if Tag = CloseTag(TagUnderline) then
        ACanvas.Font.Style := ACanvas.Font.Style - [fsUnderline] else

      if Tag = CloseTag(TagFontSize) then
        ACanvas.Font.Size := PreviousFontSize else

      if Tag = CloseTag(TagFontFamily) then
        ACanvas.Font.Name := PreviousFontFamily else

      if Tag = CloseTag(TagFontColour) then
        ACanvas.Font.Color := PreviousFontColor else

      ///////////////////////////////////////////////////
      // Tags with values
      ///////////////////////////////////////////////////
      begin
        // Get the tag value (everything after '=')
        TagValue := GetTagValue(Tag);

        if TagValue <> '' then
        begin
          // Remove the value from the tag
          Tag := copy(Tag, 1, pos('=', Tag) - 1);

          if Tag = TagFontSize then
          begin
            PreviousFontSize := ACanvas.Font.Size;
            ACanvas.Font.Size := StrToIntDef(TagValue, ACanvas.Font.Size);
          end else

          if Tag = TagFontFamily then
          begin
            PreviousFontFamily := ACanvas.Font.Name;
            ACanvas.Font.Name := TagValue;
          end;

          if Tag = TagFontColour then
          begin
            PreviousFontColor := ACanvas.Font.Color;
            ACanvas.Font.Color := ColorCodeToColor(TagValue);
          end;
        end;
      end;
    end
    else
    // Draw the character if it's not a ctrl char
    if CurrChar >= #32 then
    begin
      CharWidth := ACanvas.TextWidth(CurrChar);

      if x + CharWidth > ARect.Right then
      begin
        x := ARect.Left;

        inc(y, MaxCharHeight);
      end;

      if y + MaxCharHeight < ARect.Bottom then
      begin
        ACanvas.Brush.Style := bsClear;

        ACanvas.TextOut(x, y, CurrChar);
      end;

      x := x + CharWidth;
    end;

    inc(idx);
  end;
end;
于 2009-06-16T10:58:37.367 に答える
1

Delphi 用の字句スキャナーまたはソース コード / シンタックス ハイライター コンポーネントを購入することをお勧めします。入手可能なものはたくさんあり、ほとんどはそれほど高価ではありません。あなたの場合、いくつかをテストして、ニーズに合った十分に効率的なものを見つけたいと思うでしょう。

いくつかの例を次に示します。

非常に大きなログ ファイルを効率的に強調表示するには、テキスト ファイルの強調表示に特化したものを参照してください。それらは非常に高速でなければなりません。しかし、RichEdit も実際には前かがみではありません。

于 2009-06-13T16:17:49.657 に答える
0

既存のプレーンテキスト ログを表示したいのですが、それに色を付けますか?

ここに私が考えることができるいくつかのオプションがあります:

  • RTF を直接書き込みます。私の知る限り、TRichEdit は RTF コードへの直接アクセスを提供します。PlainText プロパティを False に切り替えてから、Text 文字列プロパティを設定するだけです。しかし...正しいRTFコードを組み立ててください。
  • ログを HTML に変換し、TWebBrowser コントロールを使用して表示します。
  • Scintilla (または別の) ハイライト コントロールを使用して、独自の構文ハイライターを展開します...

自分でログを作成している場合は、最初に TRichEdit を使用して RTF でログを生成することもできます。または、HTML または XML でログを生成することもできます (XSLT を使用して、好きなものに変換できます)。

于 2009-06-13T09:04:55.487 に答える