Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Listbox, Einträge nur teilweise anders einfärben


Friedhelm - Mo 25.11.02 19:21
Titel: Listbox, Einträge nur teilweise anders einfärben
Hallo zusammen,

ich möchte die Einträge einer LIstbox in derselben Zeile nur teilweise, in Abhängigkeit vom angezeigten Wert, z.B. 100 anders einfärben.

d.h. Wert ist 100 am Ende der Zeile habe ich einen Strich mit 100 Einheiten.

ist der Wert 50, dann soll der Strich um die Hälfte kürzer sein.
Hat dazu jemand eine Idee?
Danke für den Tip
Gruß
Friedhelm


Keldorn - Mo 25.11.02 21:14

Hallo,
wenn ich dich richtig versatnden habe, geht das, indem Du die einzelnen Items und den Hintergrund selber zeichnest.
die eigenschaft Style der listbox mußt du auf lbOwnerDrawFixed stellen

Anm: 100 ist der maximalwert, die werte der Listbox dürfen nur Zahlen sein, sonst schepperts...

ansonsten sollte der ansatz da sein.

Mfg Frank


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:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
Var x1:integer;
    arect:Trect;
begin
  with (Control as Tlistbox) do
    begin
      //anteil bestimmen
      x1:=round(strtoint(items[index])*rect.right/100);
      //Balken zeichnen - wenn Item selektiert, dann andere Farbe wählen
      arect:=rect;
      arect.Right:=x1;
      if odSelected in State then canvas.brush.color:=clgray
                             else canvas.brush.color:=clltgray;
      Canvas.fillrect(arect);
      //RestBalken weiß zeichnen
      arect:=rect;
      arect.left:=x1;
      if odSelected in State then canvas.brush.color:=clblue
                             else canvas.brush.color:=clwhite;
      Canvas.fillrect(arect);
      //Textausgeben
      Canvas.brush.style:=bsclear;
      canvas.textout(rect.left+2,rect.top+2,items[index]);
    end;
end;


Tino - Di 26.11.02 10:08

Keldorn hat folgendes geschrieben:
Anm: 100 ist der maximalwert, die werte der Listbox dürfen nur Zahlen sein, sonst schepperts...

Dazu brauch man eigentlich nur noch das OnMeasureItem-Event benutzen.

Gruß
TINO


Keldorn - Di 26.11.02 10:42

Tino hat folgendes geschrieben:
Dazu brauch man eigentlich nur noch das OnMeasureItem-Event benutzen.


wie meinst du das ?

von unterschiedlichen Höhen der Items war ja noch nicht die Rede :?

mit dem maximal-wert 100 meinte ich die x-Position, da ja sonst die Umrechnung nicht mehr richtig funzt.
mit den werten und scheppern: meinte ich das STRtoint

Mfg Frank


Tino - Di 26.11.02 10:45

Hallo,

ich habe das so verstanden das so eine Art Balken in jeweils verschiedenen Höhen angezeigt wird. Wenn das nicht der Fall sein sollte dann ist natürlich der Hinweis von mir an dieser Stelle nicht richtig!

Gruß
TINO


Friedhelm - Mi 27.11.02 16:23

Hallo zusammen,

im Prinzip hat es funktioniert. Nur muss ich den Anfangspunkt des Balkens in der Listbox hinter den gesamten String legen.

d.h.: 020102-A354-P035 !---------------hier soll der Balken hin, in

Abhängigkeit des Wertes "035" nämlich in diesem Falle 35%.

Oder kann man es verbessern?
Gruss
Friedhelm


Keldorn - Mi 27.11.02 16:33

Zitat:

Oder kann man es verbessern?


ja.
haben die Einträge alle die gleiche Länge bzw. sollen die Balken den gleichen Anfang haben?

Du mußt 3x Fillrect aufrufen und die 3 Teilbereiche zeichnen (Schrift, Balken, Balkenrest)
x1:=round(strtoint(items[index])*rect.right/100);
das rect.right/100 muß dann auch entsprechend und das arect muß jeweils angepaßt werden.
Sollte aber alles kein großes Problem sein, probiers erstmal und wenn du noch Probs hast, meldsete dich wieder

Mfg Frank


Friedhelm - Mo 02.12.02 10:35

Hallo FRank,
ich habe es probiert. Die Länge von dem String macht Ärger. Der Balken soll ab dem Audrufungszeichen bis rechts Anschlag Listbox gehen. Die 035 ist der Wert, den ich jeweils als Balken zeichnen möchte.

Gruss
Friedhelm


Keldorn - Mo 02.12.02 10:40

hallo

poste mal deinen Code von ondraw, mit der beschreibung kann ich nicht unbedingt viel anfangen und nur vermuten.

Frank


Friedhelm - Mo 02.12.02 14:36

Hallo Frank,

Also, die Länge der Balken soll von der 035 abhängen. (Das nächsten Projekt ist vielleicht 50% fertig)

Die Strings, die aufgelistet sind shen so aus: 020102-A-110345-P035

Hinter der 035 bis Ende Listbox = 100 Einheiten(0,25,50,75,100) möchte ich den Balken platzieren. Sop kann ich den Fortschritt jedes Projektes sehen.
Hier der Code:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
   x1:=round(strtoint(items[index])*rect.right/100);
   arect:=rect;
   arect.Right:=x1;

      if odSelected in State then canvas.brush.color:=clgray 
                             else canvas.brush.color:=clltgray;
  Canvas.fillrect(arect);
  arect:=rect;
  arect.left:=x1;

      if odSelected in State then canvas.brush.color:=clblue 
                             else canvas.brush.color:=clwhite;

      Canvas.fillrect(arect);
      Canvas.brush.style:=bsclear; 
      canvas.textout(rect.left+2,rect.top+2,items[index]);

Gruss
Friedhelm

(02.12. 13:53 Tino) Code-Tags hinzugefügt.


Keldorn - Mo 02.12.02 15:28

Hallo

meinen Code kannte ich :lol: :lol: ich wollte deinen sehen, du hast ja gar keinen Versuch unternommen, den Balken woanders zu zeichnen :twisted:


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:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);

const startposx = 100; //Anfangsposition des Balkens (mußt du anpassen)

Var arect : Trect;

begin
  with (Control as tlistbox) do
    begin
      //Hintergrund komplett löschen
      if odSelected in State then canvas.brush.color:=clblue
                             else canvas.brush.color:=clwhite;
      Canvas.fillrect(rect);

      //den Balken zeichnen
      arect:=rect;
      arect.Left:=Startposx;
      arect.right:=round(strtoint(items[index])*               // 1)
                        (rect.right-startposx)/100)+startposx;
      if odSelected in State then canvas.brush.color:=clgray
                             else canvas.brush.color:=clltgray;
      Canvas.fillrect(arect);

      //text ausgeben
      Canvas.brush.style:=bsclear;
      canvas.textout(rect.left+2,rect.top+2,items[index]);
    end;
end;


1) wie du diesen Wert ermittelst, ist ne andere Sache -> hier muß der Prozenzsatz stehen
die Endposition des Balkens ist das Verhältnis des Wertes zur maximal möglichen Gesamtlänge des Balkens

Mfg Frank


Friedhelm - Mo 02.12.02 19:41

Hallo Frank,

Danke für die Hilfe. Da wäre ich nicht draufgekommen. Ich habe es anders versucht. Ging nicht.Jetzt versuche ich noch herausfinden, wie der Rest von dem jeweiligen Item ignoriert werden kann.

Danke nochmals.
Gruss
Friedhelm


Friedhelm - Di 03.12.02 19:03

Hallo Frank,

ich kopiere die Prozentziffer aus dem gesamten String heraus.

Quelltext
1:
2:
3:
for yy := 0 to Listbox1.Items.Count - 1 do
                Listbox1.Items.Add
        ( copy (Listbox1.Items [yy], 39, 3));  //Prozent

das wäre denn an der Stelle: 39 drei Ziffern. In welcher Form kann man ihn den einfügen?

Quelltext
1:
2:
3:
4:
      arect.Left:=Startposx;
      arect.right:=round(strtoint(items[index])*   YY ??          // 1)

                        (rect.right-startposx)/100)+startposx;

Gruss
Friedhelm

(04.12. 08:39 Tino) Code-Tags hinzugefügt.


Keldorn - Di 03.12.02 19:34

Hallo

Zitat:
arect.right:=round(strtoint(items[index])* YY ?? // 1)

was soll das *YY denn bewirken ? :roll:

Zitat:
In welcher Form kann man ihn den einfügen?


diese Frage hast du dir doch schon selber beantwortet.
mit

Quelltext
1:
Listbox1.Items.Add( copy (Listbox1.Items [yy], 39, 3)); //Prozent                    

fügst Du die Prozentwerte in die Listbox ein um sie hier
strtoint(items[index])
wieder in eine Zahl zu wandeln um damit zu rechnen und die Balkenlänge zu ermitteln.

abgesehen davon macht

Quelltext
1:
2:
3:
for yy := 0 to Listbox1.Items.Count - 1 do
Listbox1.Items.Add
( copy (Listbox1.Items [yy], 39, 3)); //Prozent

keinen Sinn, da du die werte ja wieder in die gleiche Listbox hinzufügst :P

Mfg Frank


Friedhelm - Di 03.12.02 19:54

Hallo Frank,

ja,das war nicht gut. Aber

Quelltext
1:
( copy (Listbox1.Items [yy], 39, 3));                    

kann ich doch einer Variablen zuordnen. z.B. "P" und diese dann
hier einsetzen.

Quelltext
1:
arect.right:=round(strtoint(items[index])* P  ?? //                    

Das müsste doch laufen. Oder?

Danke für den Tip

Gruss Friedhelm

(04.12. 08:40 Tino) Code-Tags hinzugefügt.


Keldorn - Di 03.12.02 22:21

Hallo

Zitat:
Das müsste doch laufen. Oder?

nö. Allerdings sehe ich jetzt auch keinen Sinn, dir direkt zu sagen wie es richtig wäre, zumal die antwort in meinem letztem Posting steht. Außerdem soll es ja dein Programm werden und nicht meins.

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
      //den Balken zeichnen
      arect:=rect;
      arect.Left:=Startposx;
      arect.right:=round(strtoint(items[index])*               // 1)
                        (rect.right-startposx)/100)+startposx;
      if odSelected in State then canvas.brush.color:=clgray
                             else canvas.brush.color:=clltgray;
      Canvas.fillrect(arect);

Beschreib mir mal, wie das mit dem Balken zeichnen genau funktioniert und dann sehen wir weiter

Mfg Frank


Friedhelm - Mi 04.12.02 10:28

Hallo Frank
klar, ich muss selbst überlegen. Aber es liegt , denke ich , ein MIssverständnis vor. Denn meine Items sind fortlaufend so:

021231-A345-P035
021223-A543-P075
usw
viele Items und immer soll die Prozentziffer angezeigt werden. Darum verstehe ich nicht warum

Quelltext
1:
2:
3:
for yy := 0 to Listbox1.Items.Count - 1 do 
Listbox1.Items.Add 
( copy (Listbox1.Items [yy], 14, 3)); //Prozent

keinen Sinn machen soll? Ich nehme doch die Stelle 14,3 und kopiere die Ziffer, berechne sie und gehe zum nächsten Eintrag. Müssen denn nicht alle Items nacheinander angesprochen werden?

Gruss
FRiedhelm

(04.12. 10:33 Tino) Code-Tags hinzugefügt.


Keldorn - Mi 04.12.02 10:55

Hallo Friedhelm,

das macht keinen Sinn, weil Du die Items zur gleichen Listbox hinzufügst.
also steht dann in der Listbox
Zitat:

021231-A345-P035
021223-A543-P075
035
075

das Drawitem-Ereignis wird ausgelöst, wenn ein Eintrag neugezeichnet werden muß. das wird unweigerlich zu einer Exception führen, da strtoint('021231-A345-P035 ') nicht geht.
Da ich ja vorher nicht wußte, was für Einträge deine Listbox enthält bin ich nur von Zahlen (als String) ausgegangen. Dieser String wird mit strtoint(items[index]) wieder zu ner Zahl gewandelt mit der dann die Balkenlänge errechnet wird.
und jetzt frage ich dich, wenn in meinem Code beim OnDrawitem items[index] die Zahl (also die Prozentzahl) darstellt, wie es in deinem Code aussehen soll.

Meine Frage haste mir auch noch nich beantwortet :?

Mfg Frank


Friedhelm - Mi 04.12.02 11:10

Hallo FRank,

mit dem Kopieren ist mir jetzt klar. War Blödsinn. Will ja nicht die kopierten Teile wieder in die Listbox einsetzen.

NUn zu deiner Frage, das meisnt du doch?

"Beschreib mir mal, wie das mit dem Balken zeichnen genau funktioniert und dann sehen wir weiter "

meinst du damit, wie es funktionieren soll - , oder was der Code

Quelltext
1:
2:
3:
4:
5:
      //den Balken zeichnen 
      arect:=rect; 
      arect.Left:=Startposx; 
      arect.right:=round(strtoint(items[index])*
     (rect.right-startposx)/100)+startposx;

aussagt?

Gruss
Friedhelm

(04.12. 10:34 Tino) Code-Tags hinzugefügt.


Keldorn - Mi 04.12.02 11:18

Hallo,

Zitat:

meinst du damit, wie es funktionieren soll


genau, weil ich den Eindruck habe, das Du nicht richtig verstanden hast, was dort genau passiert - sonst hättest Du nicht *P und die Probleme mit dem rauskopieren etc. geschrieben.

Frank


Friedhelm - Mi 04.12.02 12:06

Hallo Frank,

1. Startposx wird festgelegt wo der Balken anfangen soll (x-Achse)

2. arect.right:=round(strtoint(items[index])* rechteck zeichnen,

3. (rect.right-startposx)/100)+startposx;
Item/Index die zahl, die in der Listbox steht.

4. damit habe ich aber nicht - wie in meinem Falle - den Teilstring verarbeitet?
Ich rechne doch einzig und allein mit den Werten, die in der Listbox stehen(wenn es nur ZAHLEN sind) UNd dass´ist in meiner ListBox ja nicht der Fall.
Mit nur Zahlen funzt es.

Eigentlich geht es mir jetzt darum, den Teilstring(Item), nämlich die 035, 075 usw als Balken hinter dem jeweiligen Eintrag zu stellen, wobei alle Einträge der LB in voler Länge bestehenbleiben.

Sehe ich die LÖsung nicht, oder ist sie so simpel??? :oops:


Gruss
Friedhelm


Keldorn - Mi 04.12.02 12:44

*aufgeb*

das arect ist das "Rechteck" des Balkens
arect.left die linke anfangsposition
arect.right dir rechte. die setzt sich zusammen aus:
rect.right-startposx ist die maximal mögliche Länge des Balkens in Pixel (also für den angenommenen max Wert 100)
rect.right ist die Breite des zu zeichnenden Items und damit auch der Listbox. Dadurch ist der Code flexibel und Größenänderungen der Listbox führen immer zum gleichen relativen Ergebnis
der Rest ist ein simpler Dreisatz:
maximale Balkenlännge = 100
meine Balkenlänge = mein Wert

daraus ergibt sich
mein wert * maximale Balkenlänge
meine Balkenlänge = ---------------------------------
100

mein Wert ist der Prozentsatz oder was auch immer. In meinem Beispiel strtoint(items[index])
und für den deinen Code : strtoint(copy (Items [index], 14, 3)).

du mußt den Prozentsatz dort rauskopieren .... so schwer?

um sicher zu sein,

Quelltext
1:
2:
3:
4:
5:
6:
7:
s:=copy (Items [index], 14, 3);
try
  wert:=strtoint(s)
except
  wert:=0;
end;
arect.right:=round(Wert*(rect.right-startposx)/100)+startposx;

is jetz nur so hier reingeklimpert, geht bestimmt noch eleganter. Sinn ist, das copy(...) trotzdem noch einen String enthaltenn könnte,
der nicht in eine Zahl gewandelt wrden kann. Damit kommst du evtl in eine Endloschleife, da erst eine Exception ausgelöste wird, evtl der Listboxeintrag neu gezeichnet wird und damit wieder eine Exception ausgelöst usw.

jetzt klar ?

Mfg Frank


Friedhelm - Mi 04.12.02 14:21

Hallo Frank,

danke für deine Mühe. Wenn ich das so lese habe ich es verstanden.
Bei mir hat z.B. beim Kopieren immer ein Komma gefehlt. :oops:

So kam ich nicht weiter.
Danke nochmal. :beer:

Gruss
Friedhelm