Autor Beitrag
delphi10
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 447
Erhaltene Danke: 2

W2K, XP, Vista64, Win7 64
RAD-Studio 2010
BeitragVerfasst: Do 26.06.08 11:42 
Hallo

Für die farbige Textausgabe aus Listboxen etc. steht ja die Möglichkeit ListBox1DrawItem() zur Verfügung um einzelne Zeilen unterschiedlich einzufärben. Die Variante, ein einzelnes Wort aus einem String zu beeinflussen, ist damit aber nicht möglich.
Das wollte ich aber realisieren, habe aber nichts einschlägiges gefunden. Also habe ich ListBox1DrawItem() etwas abgeändert. Statt den gesamten String auszugeben, löse ich ihn in einzelne Worte auf und gebe die nacheinander aus. Durch voranstellen eines Steuerzeichens kann das einzelne Wort jetzt fast beliebig formatiert werden. Gewählt habe ich § für Farbe und Fett, das # für Farbe, Fett und kursiv. Die Auswahl der Steuerzeichen ist etwas eingeschränkt, man will sie ja vielleicht auch im normalen Text verwenden können.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
Procedure TForm10.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
  Var
  ASt,                //Ausgabestring
  tAst: String;       //Teilausgabestring (einzelnes Wort)
  m,                  //Zähler durch den Ausgabestring
  l: Integer;         //Länge des Teilstrings im Canvas
  begin
    tAst := '';
    m    := 1;
    With TListBox(Control) do
    begin
      Canvas.Font.Name := 'Arial';
      Canvas.Font.Size := 10;
      Canvas.ItemHeight := 18;
      ASt := Items[Index];
      Repeat
//      ++++++++++++++++++++++++++++++++++++++++++++++++++
//      Löst den Ausgabestring in einzelne Worte auf. Delimiter ist space
        If Ast <> '' then
        repeat
          tAst := tAst + Ast[m];
          inc(m);
        until (Ast[m] = ' ') or (m >= length(Ast)+1);
//      ++++++++++++++++++++++++++++++++++++++++++++++++++
//      Entsprechend des Steuerzeichens das einzelne Wort behandeln
        If (Pos('§',tAst) >= 1) or (Pos('#',tAst) >= 1) then
        begin
          If (Pos('§',tAst) >= 1) then
          begin
            Canvas.Font.Color:=clBlue;
            Canvas.Font.Style:=[fsbold];
            Delete(tAst,Pos('§',tAst),1);
          end;
          If (Pos('#',tAst) >= 1) then
          begin
            Canvas.Font.Color:=clRed;
            Canvas.Font.Style:=[fsItalic] + [fsBold];
            Delete(tAst,Pos('#',tAst),1);
          end;
        end else
        begin
          Canvas.Font.Style:=[];
          Canvas.Font.Color:=clHotLight;
        end;
        Canvas.TextOut(Rect.Left+4, Rect.Top, tAst);   //Teilstring in das Canvas schreiben
        l := Canvas.TextWidth(tAst);                   //Länge des Teilstrings bzw. Platzbedarf im Canvas ermitteln
        Rect.Left := Rect.Left + l;                    //Zum linken X-Wert der Canvas addieren (für den nächsten Teilstring)
        If tAst = '' then Exit;
        tAst := '';
      until m >= length(Ast);
    end;
  end;


Ein Beispiel habe ich mal angehängt. Vielleicht kann's ja jemand gebrauchen. Feedback ist willkommen.

Gruß Delphi10

Edit: Groben Fehler (With TListBox(Control) do....) korrigiert. 16.02.2009

Moderiert von user profile iconChristian S.: Topic aus Algorithmen, Optimierung und Assembler verschoben am Do 26.06.2008 um 12:42
Moderiert von user profile iconChristian S.: Topic aus VCL (Visual Component Library) verschoben am Do 26.06.2008 um 12:43
Moderiert von user profile iconNarses: Topic aus der Library zurück nach VCL (Visual Component Library) verschoben am Mi 09.05.2012 um 23:40, da die Anforderungen für einen Library-Eintrag nicht erfüllt sind.
Einloggen, um Attachments anzusehen!
_________________
Salus populi suprema lex esto


Zuletzt bearbeitet von delphi10 am Mo 16.02.09 20:36, insgesamt 2-mal bearbeitet
delphi10 Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 447
Erhaltene Danke: 2

W2K, XP, Vista64, Win7 64
RAD-Studio 2010
BeitragVerfasst: So 29.06.08 16:40 
Interessiert das hier wirklich niemand? Erstaunlich.
cu delphi10

_________________
Salus populi suprema lex esto
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: So 29.06.08 17:54 
user profile icondelphi10 hat folgendes geschrieben:
Interessiert das hier wirklich niemand? Erstaunlich.

Hi! Klar gibt es Interessenten. Das ganze gefällt mir recht gut, hab allerdings noch eine paar kleine Verbesserungsvorschläge.

Denn markiere ich Items einer Listbox mit angepassten OnDrawItem tauchen plötzlich schwarze Linien unter diesen auf. (s.A.)
Ein Canvas.FillRect(Rect); am Anfang der Procedure eliminiert diese aber. ;)

Zudem wird der letzte Buchstabe eines formatierten Wortes nur fragmentiert angezeigt. (s.A.)
l := Canvas.TextWidth(tAst)+1; schafft da aber Abhilfe.

Desweiteren beginnt ein String bei mir bei eins und daher verstehe ich nicht ganz, weshalb Du hier (m >= length(Ast)+1) über die Länge des Strings hinausgehst.
Letztendlich wäre nun zu erwähnen, dass der Listbox-Style auf lbOwnerDrawVariable zustehen hat, damit es funktioniert.

Ansonsten vielen Dank!

Grüße,
Marc.
Einloggen, um Attachments anzusehen!
delphi10 Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 447
Erhaltene Danke: 2

W2K, XP, Vista64, Win7 64
RAD-Studio 2010
BeitragVerfasst: Mo 30.06.08 10:30 
Zitat:
Letztendlich wäre nun zu erwähnen, dass der Listbox-Style auf lbOwnerDrawVariable zustehen hat, damit es funktioniert.


Hmmm, es gibt viele Wege nach Rom....

Innerhalb einer INIT-Procedur wird die ListBox auf
ausblenden Delphi-Quelltext
1:
Form10.ListBox1.Style := lbOwnerDrawVariable;					

gesetzt. Im Ereignis der ListBox OnDrawItem wird jetzt die Procedure
ausblenden Delphi-Quelltext
1:
Procedure TForm10.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);					

eingesetzt. Und schon läufts - jedenfalls bei mir (Delphi10). Das werd ich aber noch mal genau verifizieren und dann berichten.

Ja, mit den Spaces am Anfang und Ende eines markierten Wortes mußte ich auch ein wenig experimentieren.

cu delphi

Moderiert von user profile iconNarses: Link entfernt

_________________
Salus populi suprema lex esto
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mo 15.12.08 19:32 
Moin!

Ich habe noch einige Anmerkungen zu deinem Code-Vorschlag:
  • Du hast user profile iconMarc.s Vorschläge und Anmerkungen bisher nur kommentiert, aber offenbar nicht in den ersten Beitrag/Code einfließen lassen, oder? (siehe Anhang)
  • Wenn man die Eigenschaften der Listbox nicht korrekt einstellt, funktioniert der Code nicht, da er ja nie aufgerufen wird. Du solltest diese erhebliche "Stolperfalle" besser deutlich im ersten Beitrag hervorheben!
  • Du verwendest hier With TListBox(Control) do den übergebenen Parameter, um auf die entsprechende Listbox zuzugreifen, warum dann aber ein paar Zeilen später Form10.Listbox1.Font.Name := 'Arial'; Direktreferenzen? So kann man die Methode ja nur für eine spezielle Listbox verwenden...
  • Wo wir gerade dabei sind: was ist, wenn ich den Font "Arial" nicht verwenden möchte? Oder eine andere Größe? Oder wenn der Benutzer zur Laufzeit selbst den Zeichensatz aussuchen können soll?
  • Es wäre schön, wenn man die verwendeten Steuerzeichen einstellen könnte, um diese Zeichen auch verwenden zu können; Alternativ wäre auch Escaping ein Ansatz
  • Du zerlegst in jedem OnDraw-Aufruf den darzustellenden String. Das ist ein potentieller Performance-Killer, noch dazu verwendest du String-by-Char-Concatenation, was ein Speicher-Killer ist. Deutlich optimaler wäre es, eine eigene Komponente von der Basisklasse abzuleiten und dieser ein internes String-Array/Liste zuzuordnen, das die zerlegten Elemente vorhält, damit das nicht jedes mal beim Zeichnen wieder gemacht werden muss. In der aktuellen Form ist dein Ansatz nur für wenige Einträge geeignet
cu
Narses
Einloggen, um Attachments anzusehen!
_________________
There are 10 types of people - those who understand binary and those who don´t.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: So 08.02.09 12:26 
Hallo!

Könntest Du etwas zu Narses' Anregungen sagen oder sie umsetzen? Danke! :-)

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
delphi10 Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 447
Erhaltene Danke: 2

W2K, XP, Vista64, Win7 64
RAD-Studio 2010
BeitragVerfasst: Mo 16.02.09 21:03 
user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe noch einige Anmerkungen zu deinem Code-Vorschlag:

Hallo Narses
Ich habe diese Methode so verstanden, dass, sollte sie jemand in sein Projekt einbauen wollen, er sie sowieso anfassen muss. Deinen Ansprüchen - wie z.Bsp. ändern des Fonts während der Laufzeit kann und sollte sie nicht genügen. Das würde ich eher im Rahmen eines Projektes akzeptieren - Ich wollte diese Methode als Idee, als Denkvorlage verstanden wissen, nicht als blind übernehmbaren Quellcode.
Zweifellos richtig ist, dass es trotzdem fehlerfrei (im Sinne von: Stürzt nicht gleich ab) sein sollte. Den ListBox-Fehler habe ich oben korrigiert, war ein Überbleibsel aus einem Test. Da hätte ich noch 27mal drüberlesen können....
Dein Vorschlag mit dem String-Array ist genial, das werde ich auf jeden Fall noch nachreichen. Brauchs ja selber *g*
Soweit erstmal
Gruß Delphi10

_________________
Salus populi suprema lex esto
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: So 01.03.09 13:18 
Schön wäre es, wenn Du noch im Beitrag verewigst, welche Einstellungen man bei der Listbox machen muss, damit die Methode richtig arbeitet. Also im Prinzip das, was Du hier beschrieben hast, nur irgendwie in den ersten Beitrag eingearbeitet.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".