Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - 2 Listen miteinander vergleichen UND mit einer was tun..
Terra23 - So 17.02.13 19:45
Titel: 2 Listen miteinander vergleichen UND mit einer was tun..
In einem
anderen Thread [
http://www.entwickler-ecke.de/viewtopic.php?p=673408#673408] 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
WasWeißDennIch - 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.
Terra23 - 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.
jfheins - Mo 18.02.13 03:24
Terra23 hat folgendes geschrieben : |
Ich erhalte zwar die richtigen Werte zurück aber nach der letzten Meldung erhalte ich eine Indexüberschreitungs-Meldung. |
Logisch. Das ist aber wirklich offensichtlich ;-) [meta]Du iteriert über eine Liste und greifst mit dem Index auf eine andere zu. Das klappt nur wenn beide Listen gleich lang sind. Das ist offensichtlich nicht der Fall.[/meta]
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; |
Terra23 - Di 19.02.13 00:20
Danke, jfheins. Das war natürlich ein sehr dummer Fehler, muss ich ja zugeben. Leider konnte ich über die Hilfe und auch über Easy Delphi Helper nicht wirklich rausfinden, was "IndexOf" macht. Easy Delphi Helper liefert mir immer nur fertige Beispiele / Codes und die Hilfe lässt sich in Win 8 nicht aufrufen.
Wie dem auch sei: Ich weiß nun, wie ich herausfinde, ob und wo sich Items einer Liste in einer anderen Liste befinden. Nun sollen die an der Stelle eben eingefärbt werden. Wie man einfärbt, weiß ich.
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?
Terra23 - 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; |
WasWeißDennIch - 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 - 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.
Terra23 - 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.
WasWeißDennIch - 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 - 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; |
WasWeißDennIch - 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 - 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.
jfheins - Di 19.02.13 22:38
Nimm doch ein set - sofern du nicht mehr als 255 Items hast:
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:
| 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; |
Terra23 - 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
WasWeißDennIch - 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):
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: 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]
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!