Autor Beitrag
Terra23
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 17.02.13 19:45 
In einem anderen Thread hatte ich mal gefragt, wie man 2 Listboxen miteinander vergleicht. Das klappt auch dank user profile iconjaenicke 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Mo 18.02.13 03:24 
user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
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]

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Di 19.02.13 00:20 
user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
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]

ausblenden 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;


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?

_________________
Hasta La Victoria Siempre
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Di 19.02.13 09:03 
user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Di 19.02.13 18:36 
Hmm. OK, soweit klar. Aber welche Parameter übergebe ich denn dann?

ausblenden 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Di 19.02.13 19:58 
OK, das könnte funktionieren, wenn ich nicht irgendeinen Mist gebaut hätte.

Dieser Code...

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Di 19.02.13 20:25 
Dann hast Du wohl etwas falsch berechnet oder so. Ganz einfaches Beispiel (Listbox.Style ist lbOwnerDrawFixed):
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Di 19.02.13 22:38 
Nimm doch ein set - sofern du nicht mehr als 255 Items hast:

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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 19.02.13 22:54 
user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
die Hilfe lässt sich in Win 8 nicht aufrufen.
Weil du das entsprechende Update nicht installiert hast. :zwinker:
www.microsoft.com/de...etails.aspx?id=35449

Für diesen Beitrag haben gedankt: Terra23
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Mi 20.02.13 09:04 
user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
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):
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:
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;

{ TTestClass }

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;

{ TfrmDemo }

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]