2009-06-13 10 views
5

मुझे डेल्फी 200 9 में एक स्वरूपित लॉग प्रदर्शित करने की आवश्यकता है। स्वरूपण को HTML की सभी सुविधाओं को लागू करने की आवश्यकता नहीं है, लेकिन एक छोटा सबसेट उदा। रंग, फ़ॉन्ट शैली इत्यादिमैं डेल्फी में एक स्वरूपित (रंग, शैली आदि) लॉग कैसे प्रदर्शित करूं?

वर्तमान में मैं एक TRichEdit और अपने स्वयं के स्वामित्व टैग का उपयोग कर रहा हूं उदा। यह नीला है। यह एक TRichEdit के साथ काम करने के लिए बहुत मजबूत है क्योंकि आरटीएफ पाठ में कोई सीधी पहुंच नहीं है। उदाहरण के लिए, टेक्स्ट नीले रंग को रंगने के लिए मुझे यह करना होगा:

  1. टैग निकालने वाले संलग्न पाठ को पार्स करें, यह पता लगाने के लिए कि किस पाठ को स्वरूपित किया जाना चाहिए और कैसे।
  2. टेक्स्ट का चयन करें।
  3. प्रारूपण लागू करें।
  4. टेक्स्ट को अचयनित करें और चयन को अगले अनुलग्नक के लिए तैयार पाठ के अंत में ले जाएं।

यह सब हैकी और धीमी है। क्या आप TRichEdit या किसी अन्य नियंत्रण के साथ ऐसा करने के लिए बेहतर (तेज़) तरीका जानते हैं जो नौकरी के लिए बेहतर अनुकूल है?

मुझे यह उल्लेख करना चाहिए कि मैंने एक TWebBrowser में HTML का उपयोग करने पर विचार किया है। इस दृष्टिकोण के साथ समस्या यह है कि लॉग 1 से 100000 लाइनों से कहीं भी हो सकता है। यदि मैं एक सामान्य एचटीएमएल दर्शक का उपयोग करता हूं तो मुझे बस इसे जोड़ने के बजाए हर बार पूरे पाठ को सेट करने की आवश्यकता होती है।

इसके अतिरिक्त, लॉग को वास्तविक समय में अपडेट करने की आवश्यकता है क्योंकि मैं इसे लाइन जोड़ता हूं। एक फ़ाइल से बस पढ़ा और एक बार प्रदर्शित नहीं किया।

उत्तर

9

सरल समाधान: कस्टम ड्रॉ विधियों के साथ एक TListBox का उपयोग करें, और लॉग प्रविष्टियों को ऑब्जेक्ट्स का उपयोग करके एक TObjectList में डालें जिसमें केवल मूलभूत जानकारी है, स्वरूपण नहीं (यह प्रेजेंटेशन कोड में लागू होगा)।

या वर्चुअल स्ट्रिंग सूची/VirtualTreeView घटक का उपयोग करें। केवल उन्हीं वस्तुओं को प्रदर्शित करने की आवश्यकता होगी, यह संसाधनों को बचाएगा।

+1

+1 यह एकमात्र कमी है कि पाठ का चयन नहीं किया जा सकता है और क्लिपबोर्ड पर कॉपी किया जा सकता है। – gabr

+0

के लिए – mghie

0

मैं इकट्ठा करता हूं कि आप एक मौजूदा सादे-पाठ लॉग दिखाना चाहते हैं, लेकिन इसमें रंग लागू करें?

यहां कुछ विकल्प दिए मैं के बारे में सोच सकते हैं:

  • सीधे आरटीएफ लेखन; AFAIK, TRichEdit आरटीएफ कोड तक सीधे पहुंच प्रदान करता है; बस PlainText प्रॉपर्टी को गलत पर स्विच करें, फिर टेक्स्ट स्ट्रिंग प्रॉपर्टी सेट करें। लेकिन ... सही भाग्य सही आरटीएफ कोड को इकट्ठा करना।
  • अपना लॉग एचटीएमएल में कनवर्ट करें, और इसे प्रदर्शित करने के लिए TWebBrowser नियंत्रण का उपयोग करें।
  • उपयोग Scintilla (या अन्य) नियंत्रण पर प्रकाश डाला, और अपने खुद के वाक्य रचना हाइलाइटर रोल ...

आप अपने आप को प्रवेश करते है, तो आप भी एक TRichEdit प्रयोग आरटीएफ में लॉग उत्पन्न करने के लिए कर सकता है लिख रहे हैं प्रथम स्थान। या आप एचटीएमएल में लॉग इन कर सकते हैं, या एक्सएमएल में (जिसे एक्सएसएलटी का उपयोग करके जो कुछ भी आप पसंद करते हैं उसे बदल सकते हैं)।

+0

बिल्कुल नहीं।मुझे एक लॉग चाहिए जो वास्तविक समय में प्रदर्शित और स्क्रॉल करता है क्योंकि मैं इसे अतिरिक्त लाइन जोड़ता हूं। वर्चुअल ट्री व्यू – norgepaul

4

अपनी लॉग मान लिया जाये कि 1,000,000 लाइनों तक आप (mjustin के रूप में पता चलता है) एक TListBox

Style := lbVirtualOwnerDraw; 
OnDrawItem := ListDrawItem; // your own function (example in help file) 
  1. साथ (और मैं 100-1,000,000 संभाल) HTML या आरटीएफ, साफ समाधान का उपयोग कर रहा है उपयोग करने के लिए भूल सकता है अपने डेटा सरणी को परिभाषित करें कि जो भी प्रारूप शेष एप्लिकेशन के लिए उपयोगी है। मैं एक साधारण LogObject के साथ जाओ।
  2. ऑब्जेक्टलिस्ट में सभी लॉगऑब्जेक्ट्स को स्टोर करें, हर बार सूची में कोई परिवर्तन होता है (जोड़ें, हटाएं), TListBox को समायोजित करें। नई ऑब्जेक्टलिस्ट गिनती से मेल खाने के लिए गणना करें।
  3. सूची परिभाषित करें खुद को इंडेक्स लेने के लिए तैयार करें और आप ऑब्जेक्टलिस्ट (डेटाबेस, जो भी ..) से जानकारी प्राप्त कर सकते हैं और मांग पर पार्स कर सकते हैं।

क्योंकि आप केवल एक ही समय में कुछ प्रविष्टियां देखेंगे, "मांग पर पार्सिंग" दृष्टिकोण काफी बेहतर है क्योंकि लोड समय पर "धीमा" नहीं होता है क्योंकि आप सभी मिलियन लाइनों को पार्स करने का प्रयास करते हैं।

आपकी वास्तविक समस्या को नहीं जानना मैं बस इतना कह सकता हूं कि मेरे अनुभव में यह एक ऐसी तकनीक है जिसे एक बार सीखा और महारत हासिल किया जाता है, अधिकांश डेटा उन्मुख अनुप्रयोग में उपयोगी होता है।

संवर्धन में सूची बॉक्स के ऊपर हेडर नियंत्रण को जोड़ना शामिल है (मैं उन्हें एक पैनल में एक साथ लपेटता हूं) और आप बेहतर TListView नियंत्रण बना सकते हैं। हेडर कंट्रोल पर क्लिक इवेंट में थोड़ा सा तर्क संलग्न करें और आप अपनी ऑब्जेक्ट सूची को सॉर्ट कर सकते हैं और आपको केवल सूची सूची को कॉल करने के लिए सूचीबॉक्स कॉल करें। दृश्य को रीफ्रेश करने के लिए सत्यापित करें (जब यह कर सकता है)।

++ रीयलटाइम अपडेटिंग के लिए। मैं फिलहाल ऐसा करता हूं, ListBox.Count को समायोजित करने के लिए टाइमर ईवेंट ट्रिगर करना है क्योंकि आप सूची बॉक्स को 1000 बार एक बार अपडेट नहीं करना चाहते हैं .. :-)

+0

यदि आप 100000-300000 परिमाण पर जाते हैं तो मैं tstrings/tstringlist के साथ कुछ भी उपयोग नहीं करता। सूचक सूची के पुनर्वितरण आपकी याददाश्त के स्विस पनीर बनाते हैं। –

1

आप एक व्याख्यात्मक स्कैनर खरीदना चाहेंगे या डेल्फी के लिए स्रोत कोड/वाक्यविन्यास हाइलाइटर घटक। बहुत सारे उपलब्ध हैं और अधिकांश बहुत महंगा नहीं हैं। आपके मामले में, आप कुछ परीक्षण करना चाहेंगे और अपनी जरूरतों के लिए पर्याप्त कुशल खोज लेंगे।

कुछ उदाहरण हैं:

एक बहुत बड़ी लॉग फ़ाइल को हाइलाइट करने में दक्षता के लिए, उन लोगों को देखें जो टेक्स्ट फ़ाइलों को हाइलाइट करने में विशेषज्ञ हैं। वे बेहद तेज़ होना चाहिए। लेकिन RichEdit वास्तव में कोई स्लच नहीं है।

+1

टेक्स्ट एडिट नियंत्रण/दर्शक को सूची बॉक्स या ग्रिड नियंत्रणों पर लाभ होता है जो वे पाठ को चुनने और कॉपी करने की अनुमति देते हैं। स्किंटिला निश्चित रूप से ओपन सोर्स भी है, और इसमें अतिरिक्त लाभ है (उदाहरण के लिए टीएसआईएनएडिट पर) कि स्टाइलिंग जानकारी प्रति चरित्र बनाए रखी जाती है और इसे उपयोगकर्ता कोड में स्वतंत्र रूप से सेट किया जा सकता है - यह केवल सिंटैक्स हाइलाइटिंग घटक नहीं है, इसका उपयोग केवल किया जा सकता है साथ ही फ्री-फॉर्म टेक्स्ट के लिए जहां स्टाइलिंग जानकारी एक और तरीके से निर्धारित की जाती है। यह लॉग टेक्स्ट के लिए एक बेहतर फिट होना चाहिए। – mghie

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;