2009-06-13 89 views
5

我需要在Delphi 2009中顯示格式化的日誌。格式不一定要實現說html的所有功能,但是一小部分例如顏色,字體樣式等。如何在Delphi中顯示格式化(顏色,樣式等)日誌?

目前我正在使用TRichEdit和我自己的專有標籤例如這是藍色的。由於不能直接訪問RTF文本,因此將它與TRichEdit一起使用是非常令人費解的。例如,要顏色文字藍色我必須:

  1. 解析附加文本提取標籤,找出需要格式化和怎麼樣的文字。
  2. 選擇文字。
  3. 應用格式。
  4. 取消選擇文本並將選定內容移動到準備進行下一個附加操作的文本末尾。

所有這些都很慢,也很慢。您是否知道使用TRichEdit或另一種更適合該工作的控件可以實現更好(更快)的方式?

我應該提到我已經考慮在TWebBrowser中使用HTML。這種方法的問題是日誌的長度可能在1到100000行之間。如果我使用普通的html查看器,我需要每次都設置整個文本,而不是簡單地附加它。

此外,日誌需要實時更新,因爲我添加了行。不是簡單地從文件中讀取並顯示一次。

回答

9

簡單的解決方案:使用具有自定義繪製方法的TListBox,並使用僅包含基本信息而不是格式(這將應用於表示代碼中)的對象將日誌條目放入TObjectList中。使用虛擬字符串列表/ VirtualTreeView組件。只有需要顯示的項目纔會被渲染,這將節省資源。

+1

Virtual TreeView的+1 – gabr 2009-06-13 10:03:33

+0

這有唯一的缺點,即文本無法選擇並複製到剪貼板。 – mghie 2009-06-13 18:21:18

0

我收集你想要顯示一個現有的純文本日誌,但應用它的顏色?

這是我能想到的幾個選項:

  • 直接編寫RTF; AFAIK,TRichEdit確實提供對RTF代碼的直接訪問;只需將PlainText屬性切換爲False,然後設置Text字符串屬性即可。但是...祝你好運,組裝正確的RTF代碼。
  • 將您的日誌轉換爲HTML,並使用TWebBrowser控件來顯示它。
  • 使用Scintilla(或其他),突出的控制,並推出自己的語法高亮...

如果你正在寫日誌自己,你也可以使用一個TRichEdit生成的日誌中RTF第一個地方。或者,您可以使用HTML或XML格式生成日誌(然後使用XSLT將其轉換爲任何您喜歡的內容)。

+0

不完全是。我想要一個顯示並實時滾動的日誌,因爲我在其上添加了額外的行。 – norgepaul 2009-06-13 09:25:50

4

假設你的日誌爲100萬行代碼,你可以使用HTML或RTF,在乾淨的解決方案(和我處理100-1,000,000)是使用與

Style := lbVirtualOwnerDraw; 
OnDrawItem := ListDrawItem; // your own function (example in help file) 
  1. 忘記(如mjustin建議)一個的TListBox以任何適用於其他應用程序的格式定義數據數組。我用一個簡單的LogObject去。
  2. 商店所有的鏈表類LogObjects,每次有是列表中的變化(添加,刪除),調整TListBox.Count以匹配新的鏈表類計數。
  3. 定義ListDrawItem自己採取的指數,你可以從YOUE鏈表類的信息(數據庫,無論..)和需求分析。

因爲您一次只能查看幾個條目,所以「按需解析」方法明顯更好,因爲在您嘗試解析所有百萬行時,在加載時沒有「減速」。

不知道您的實際問題,我只能說,在我的經驗是,一旦學習和掌握在大多數面向數據的應用程序非常有用的技術。

增強包括attacheing上述列表框中選擇一個標題控制(I在面板一起將它們包裝)並且可以創建一個優越的TListView控制。將一些排序邏輯附加到標題控件上的click事件上,你可以對你的對象列表進行排序,你所要做的就是調用ListBox.Invalidate來刷新視圖(當它可以)。

++用於實時更新。我現在這樣做,是要觸發一個計時器事件來調整ListBox.Count,因爲您不想每秒更新一次列表框1000次.. :-)

+0

如果超過100000-300000的數量級,我不會使用tstrings/tstringlist。指針列表的重新分配會讓你的記憶變成瑞士奶酪。 – 2009-06-13 23:21:29

1

您可能想要購買一個詞法掃描儀或Delphi的源代碼/語法高亮組件。有很多可用的,大部分都不是很貴。在你的情況下,你會想測試一些,找到一個足夠滿足你的需求的效率。

有幾個例子是:

爲了突出顯示非常大的日誌文件的效率,請查看專門突出顯示文本文件的內容。他們應該非常快。但是RichEdit實際上也不是懶散。

1

,如果你決定使用一個TListBox中所建議的,請確保您允許用戶複製他們正在查看到剪貼板線的細節。沒有比不能從日誌中複製行更糟糕的事了。

0

對於那些有興趣的,這裏是我最終使用的代碼。如果將它附加到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; 
相關問題