Autor |
Beitrag |
Terra23
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: So 17.02.13 19:45
In einem anderen Thread hatte ich mal gefragt, wie man 2 Listboxen miteinander vergleicht. Das klappt auch dank jaenicke sehr, sehr gut.
Nun würde ich gern die Ergebnisse nicht nur angezeigt bekommen sondern die gefundenen Ergebnisse in der ersten Liste einfärben. Den Code fürs Einfärben habe ich, aber irgendwie bin ich zu blöd, das umzusetzen. Kann mir jemand auf die Sprünge helfen?
Mein Problem ist, dass in dem Code von jaenicke ja die Strings aus TempList angezeigt werden. Und TempList[I] ist ja nicht gleichbedeutend mit "Liste_Staedte[I]". Ich habe mal nen Screen angehängt, damit ihr wisst, was ich meine (ist nur ein Beispiel).
Die erste Liste heißt "Liste_Staedte", die anderen "Liste_Rot", "Liste_Gelb" und "Liste_Gruen".
Ich bedanke mich schon Mal im Vorraus für eure Denkanstöße.
Gruß,
Terra
Einloggen, um Attachments anzusehen!
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: So 17.02.13 19:57
Die einfachste Möglichkeit: jede Teilliste durchgehen, mit IndexOf den Index in der Hauptliste ermitteln und wenn größer als -1, das Hauptlistenitem mit diesem Index einfärben.
Für diesen Beitrag haben gedankt: Terra23
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: So 17.02.13 20:35
Danke für den Denkanstoß. Das scheint nichtmal so kompliziert zu sein, wie ich dachte. Ich bin gerade voll in Fahrt und ich glaube, es funktioniert. Ich melde mich hier nochmal, wenn es klappt..
Edit: Also ich kriege es hin, dass ich auf nen Button-Klick anzeigen lasse, ob und wo das Item vorkommt.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| var I, J: Integer;
For I := 0 To Liste_Staedte.Items.Count - 1 Do Begin J := Liste_Staedte.Items.IndexOf(Liste_Rot.Items[I]); If J > -1 Then ShowMessage(Liste_Staedte.Items[J] + ' gefunden an Position ' + IntToStr(J)); End; |
Ich erhalte zwar die richtigen Werte zurück aber nach der letzten Meldung erhalte ich eine Indexüberschreitungs-Meldung.
_________________ Hasta La Victoria Siempre
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Mo 18.02.13 03:24
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 00:20
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 19.02.13 09:03
Terra23 hat folgendes geschrieben : | PROBLEMATISCH für mich an dieser Stelle ist aber, dass ich ja ins OnItemDraw-Ereignis muss. Kann ich das Färben nicht vom Button aus erledigen? |
Sicher, sorge einfach dafür, dass sich die Listbox neu zeichnet, dann wird auch das OnDrawItem für jede Zeile ausgelöst
[edit] Statt der Delphi-Hilfe kannst Du auch die Referenz der Delphi-PRAXiS benutzen, da steht IndexOf recht gut beschrieben. [/edit]
Für diesen Beitrag haben gedankt: Terra23
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 18:36
Hmm. OK, soweit klar. Aber welche Parameter übergebe ich denn dann?
Delphi-Quelltext 1:
| OnDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState) |
Für Control würde ich Liste_Staedte übergeben wollen und für Index den Index des Items. Aber was übergebe ich für die anderen beiden Parameter?
Mein aktueller Code schaut so aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure TForm1.Button1Click(Sender: TObject); var I, J: Integer; begin For I := 0 To Liste_Rot.Items.Count - 1 Do Begin J := Liste_Staedte.Items.IndexOf(Liste_Rot.Items[I]); If J > -1 Then Begin ShowMessage(Liste_Staedte.Items[J] + ' gefunden an Position ' + IntToStr(J)); Font.Color := clRed; Liste_Staedte.OnDrawItem(Liste_Staedte, J, ???, ???); End; End; end; |
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 19.02.13 19:40
Gar nichts. Du sollst nicht den Ereignishandler aufrufen, sondern das Ereignis selbst auslösen. Das ginge z.B. mit TListBox.Update.
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 19:58
OK, das könnte funktionieren, wenn ich nicht irgendeinen Mist gebaut hätte.
Dieser Code...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TForm1.Button1Click(Sender: TObject); var I, J: Integer; begin For I := 0 To Liste_Rot.Items.Count - 1 Do Begin J := Liste_Staedte.Items.IndexOf(Liste_Rot.Items[I]); If J > -1 Then Begin ShowMessage(Liste_Staedte.Items[J] + ' gefunden an Position ' + IntToStr(J)); With Liste_Staedte As TListBox Do Begin Canvas.FillRect(Liste_Staedte.ItemRect(J)); Canvas.Font.Color := clRed; Canvas.TextOut(Liste_Staedte.Left + 2, Liste_Staedte.Top, Items[J]); End; Liste_Staedte.Update; End; End; end; |
... macht etwas sehr seltsames, was wohl zu 100% an der Übergabe von Liste_Staedte.Left + 2, Liste_Staedte.Top liegt.
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 19.02.13 20:06
Alles, was mit dem Zeichnen zu tun hat, gehört in das OnDrawItem-Event. Die übergebenen Parameter kannst Du hier nachlesen. Im ButtonClick rufst Du dann einfach ListBox.Update auf, das veranlasst das Neuzeichnen.
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 20:16
Das hatte ich zuerst auch so, allerdings hat das dann dafür gesorgt, dass die gesamte ListBox rot gefärbt wurde.
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 19.02.13 20:25
Dann hast Du wohl etwas falsch berechnet oder so. Ganz einfaches Beispiel (Listbox.Style ist lbOwnerDrawFixed):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var cv: TCanvas; begin cv := (Control as TListBox).Canvas; if Index mod 3 = 0 then cv.Brush.Color := clRed else if Index mod 2 = 0 then cv.Brush.Color := clYellow; cv.FillRect(Rect); cv.TextOut(Rect.Left + 2, Rect.Top + 2, (Control as TListBox).Items[Index]); end; |
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 20:43
@WasWeißDennIch: Lass gut sein. Ich bin heute absolut neben der Spur und kriege absolut gar nix auf die Reihe. Es gibt Tage, da läuft alles von der Hand und es gibt Tage, da läuft rein gar nix und von denen habe ich in letzter Zeit leider zu viele.
Den Code, den du gepostet hast, hatte ich so ähnlich auch schon. Ich wusste allerdings nicht, wie ich INDEX die richtige Zahl zuweise.
Daher habe ich es jetzt mal mit einer globalen Variablen namens "IndexOfDrawItem_Red" deklariert.
So rufe ich das auf, allerdings passiert rein gar nix und ich bin langsam echt frustriert.
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:
| procedure TForm1.Button1Click(Sender: TObject); var I, J: Integer; begin For I := 0 To Liste_Rot.Items.Count - 1 Do Begin J := Liste_Staedte.Items.IndexOf(Liste_Rot.Items[I]); If J > -1 Then Begin IndexOfDrawItem_Red := J; ShowMessage(Liste_Staedte.Items[J] + ' gefunden an Position ' + IntToStr(J)); Liste_Staedte.Update; End; End; end;
procedure TForm1.Liste_StaedteDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var Cv: TCanvas; begin Cv := (Control as TListBox).Canvas; If Index = IndexOfDrawItem_Red Then Begin Cv.Font.Color := clRed; Cv.FillRect(Rect); Cv.TextOut(Rect.Left + 2, Rect.Top, (Control as TListBox).Items[Index]); End; end; |
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 19.02.13 20:51
Verlagere doch die ganze Abfrage-Geschichte ins OnDrawItem, so dass im ButtonClick nur noch der Update-Befehl steht. Das hat allerdings den Nachteil, dass das alles bei jedem Zeichnen der ListBox durchlaufen wird, also auch beim Wiederherstellen nach Minimieren oder ähnlichen Dingen. Alternativ könnte man da ggf. TStrings.Objects missbrauchen, aber das dürfte bei nur wenigen Einträgen in den ListBoxen etwas oversized sein.
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 21:04
Eben genau das soll es ja nicht tun. Es soll nur auf den Button-Click eingefärbt werden. Ich hab mir mal überlegt, evtl. ne Boolean-Variale mit einzubauen ins OnDrawItem-Event, die dafür sorgt, dass eben nur neu gezeichnet wird (in rot) wenn True. Und True würde es nur werden, wenn der Button geklickt wird.
_________________ Hasta La Victoria Siempre
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Di 19.02.13 22:38
Nimm doch ein set - sofern du nicht mehr als 255 Items hast:
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:
| private redItems: set of Byte; end; implementation
procedure TForm1.Button1Click(Sender: TObject); var I, J: Integer; begin For I := 0 To Liste_Rot.Items.Count - 1 Do Begin J := Liste_Staedte.Items.IndexOf(Liste_Rot.Items[I]); If J > -1 Then Begin reditems = reditems + [Byte(J)]; End; End; Liste_Staedte.Invalidate; end;
procedure TForm1.Liste_StaedteDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var Cv: TCanvas; begin Cv := (Control as TListBox).Canvas; if Index in redItems then Cv.Font.Color := clRed; else Cv.Font.Color := clBlack;
Cv.Font.Color := clRed; Cv.FillRect(Rect); Cv.TextOut(Rect.Left + 2, Rect.Top, (Control as TListBox).Items[Index]); end; |
Für diesen Beitrag haben gedankt: Terra23
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 19.02.13 22:54
Für diesen Beitrag haben gedankt: Terra23
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: Di 19.02.13 23:41
@jfheins: Danke für den Tipp und den Beispielcode. Das funktioniert tadellos. Vielen, vielen Dank.
@jaenicke: Stimmt, dieses Update fehlt. Ich dachte komischerweise immer, es würden sich solche Dinge mit Windows-Update automatisch installieren. Danke dir für den Link.
Gruß,
Terra
_________________ Hasta La Victoria Siempre
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Mi 20.02.13 09:04
Terra23 hat folgendes geschrieben : | Eben genau das soll es ja nicht tun. Es soll nur auf den Button-Click eingefärbt werden. Ich hab mir mal überlegt, evtl. ne Boolean-Variale mit einzubauen ins OnDrawItem-Event, die dafür sorgt, dass eben nur neu gezeichnet wird (in rot) wenn True. Und True würde es nur werden, wenn der Button geklickt wird. |
Ja, und das könntest Du im entsprechenden Objekt zum Item hinterlegen. Man ändert also die Objekteigenschaften und löst ein Neuzeichnen der Listbox aus. Diese wertet dann das entsprechende Objekt im OnDrawItem aus und färbt entsprechend ein.
[edit] Auch dazu ein kleines Beispiel (kompletter Implementation-Abschnitt, eine ListBox und ein Button auf dem Formular):
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: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78:
| type TTestType = (ttOne, ttTwo, ttThree);
TTestClass = class private FTestType: TTestType; FTestName: string; procedure SetTestType(const Value: TTestType); public property TestType: TTestType read FTestType write SetTestType; property TestName: string read FTestName; end;
procedure TTestClass.SetTestType(const Value: TTestType); const TestStrings: array[TTestType] of string = ('Typ Eins', 'Typ Zwei', 'Typ Drei'); begin FTestType := Value; FTestName := TestStrings[Value]; end;
procedure TfrmDemo.Button1Click(Sender: TObject); var i: integer; NewTyp: TTestClass; begin for i := 0 to ListBox1.Items.Count - 1 do begin NewTyp := ListBox1.Items.Objects[i] as TTestClass; if not Assigned(NewTyp) then begin NewTyp := TTestClass.Create; ListBox1.Items.Objects[i] := NewTyp; end; NewTyp.TestType := TTestType(Random(3)); ListBox1.Items[i] := NewTyp.TestName; end; end;
procedure TfrmDemo.FormDestroy(Sender: TObject); var i: integer; begin for i := 0 to ListBox1.Items.Count - 1 do ListBox1.Items.Objects[i].Free; end;
procedure TfrmDemo.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var ItemObject: TTestClass; lb: TListBox; begin lb := Control as TListBox; ItemObject := lb.Items.Objects[Index] as TTestClass; if Assigned(ItemObject) then begin case ItemObject.TestType of ttOne: lb.Canvas.Brush.Color := clRed; ttTwo: lb.Canvas.Brush.Color := clYellow; ttThree: lb.Canvas.Brush.Color := clAqua; end; lb.Canvas.FillRect(Rect); end; lb.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, lb.Items[Index]); end;
initialization Randomize;
end. | [/edit]
|
|