Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Listview Zeilen färben, On Custom DrawItem (https://www.delphipraxis.net/111722-listview-zeilen-faerben-custom-drawitem.html)

Centrii 8. Apr 2008 12:41


Listview Zeilen färben, On Custom DrawItem
 
Hi,

hab da mal wieder ein kleines Problem.
Ich habe in meinem Programm verschiedene Clients, jeder Client hat in der Listview eine eigene Farbe
und jeder Client schreibt werte in eine Zeile/n, bzw. in eine Spalte/n dieser Zeile/n.
Das einfärben der Zeilen funktioniert wunderbar, nur passiert es ab und zu, dass ein Client in ein
SubItem schreibt nur das subItem gefärbt wird, nicht aber das ganze Item. Sieht halt ein wenig unschön aus.
Ich habe die Listview auf

Delphi-Quellcode:
Listview.DoubleBuffered:=true;
gesetzt. Leider flimmert die Listview trotzdem ziemlich stark, wenn ich jedesmal wenn OnCustomDrawItem
aufgerufen wird,

Delphi-Quellcode:
Listview.update;
aufrufe. Das ist bis jetzt aber die einzige Lösung die ich gefunden habe für das Problem.
Hier meine OnCustomDrawItem Procedure:

Delphi-Quellcode:
procedure TfDLMain.ListViewCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var i        :Integer;
    liItem   :TOPCItem;
    OPCClient :TOPCCLient;
begin
  Lock_Draw.Enter;                                                             // Critical Section Enter
  if OnDisconnectAll = false then begin
   if fClient_Auswahl.OPCList_3.Items.Count > 1 then begin                     // Liste der Clients, nur faerben wenn mehr als 1 Client vorhanden
     if item.Caption <> '' then begin
       try                                                                    
         liItem:=fDLMain.ClientCheck(item.caption);                            // zugehoeriger Client zum Item ermitteln
         if assigned(liItem) then begin                                        // wenn noch vorhanden
           OPCClient:=liItem.OpcGroup.OpcClient;                               // Client zuweisen
           Sender.Canvas.Brush.Color := OPCFarben[fclient_Auswahl.OPCList_3.Items.IndexOfObject(OPCClient)];     // Farbe auswaehlen
           if OPCClient.Tag = 2 then item.SubItems[2] := 'bad';
           Application.ProcessMessages;
         end
         else if item.SubItems[2] <> 'bad' then begin
           item.SubItems[2] := 'bad';
           Sender.Canvas.Brush.Color := clSilver;
         end
         else begin
           Sender.Canvas.Brush.Color := clSilver;
         end;
       except
         On E: Exception do begin
           AddToLog('OPC-DataLogger:main,ListViewCustomDrawItem: ',E.Message,1,7,False);
         end;
       end;
     end;
   end;
   Lock_Draw.Leave;                                                             // Critical Section Leave
  end;
end;
wenn z.B. jetzt eine Verbindung zu einem Client verloren geht, geht das subItem[2] auf 'bad' und Color := clSilver;
das funktioniert auch alles soweit, aber wie gesagt, leider nicht immer, manchmal wird nur das Subitem gefärbt. In dem Listview können
manchmal schon 150 Einträge drin sein und jeder eintrag schreibt ca. sekündlich einen neuen Wert in die Liste.

Zusätzlich sei erwähnt, dass ich zuvor bei jedem Aufruf der OnCustomDrawItem die ganze Listview durchgerattert bin und alle ListItems, mit der
für sie vorgegebenen Farbe, eingefärbt habe. Das kostet aber unglaublich viel Performance, sobald ein paar einträge in der Liste sind...

Hat jemand eine Idee, wie ich das hinbekommen kann??

Gruß Ruben

hoika 8. Apr 2008 13:09

Re: Listview Zeilen färben, On Custom DrawItem
 
Hallo,

warum benutzt du nicht das .Data property des TListItems,
um dort dein Objekt zu speichern, wen du das TListItem anlegst ?
Dann kannst du im OnDraw direkt auf alle Felder deines Objects zugreifen
(type cast auf das Data vorausgesetzt).

Deine critical section kannst du übrigens weglassen,
dass OnDraw Event wird komplett durchlaufen.

Ausserdem brauchst du kein Application.ProcessMessages;


Heiko

Centrii 8. Apr 2008 15:26

Re: Listview Zeilen färben, On Custom DrawItem
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für den Tipp.
Hab es jetzt mal so umgebaut wie du gesagt hast, leider passiert sowas (siehe Anhang) immer noch...

marabu 8. Apr 2008 16:22

Re: Listview Zeilen färben, On Custom DrawItem
 
Hallo Ruben,

wenn du beim Ereignis OnDrawItem() versuchst alle Items zu färben, dann machst du einen gewaltigen Fehler. Prinzipiell signalisierst du mit Invalidate() oder InvalidateRect() deinen Wunsch nach Neuzeichnung, das ListView Control übergibt dann für jedes Item bzw. SubItem die Kontrolle deinen Ereignisbehandlungsroutinen. Das geschieht sehr ökonomisch und führt in Verbindung mit deinem DoubleBuffering kaum zum Flackern. Die Daten würde ich auch nicht vom ListView Control verwalten lassen - Stichwort: OwnerData.

Grüße vom marabu

Centrii 8. Apr 2008 16:36

Re: Listview Zeilen färben, On Custom DrawItem
 
Danke Marabu

Ich werde mal versuchen umzusetzen was du mir geschrieben hast, auch wenn ich ehrlich gesagt jetzt noch nicht ganz verstehe was ich machen soll :wink:
Wo soll ich den die Items färben wenn nicht im OnCustomDrawItem?

Gruß Ruben

marabu 8. Apr 2008 16:54

Re: Listview Zeilen färben, On Custom DrawItem
 
Was das Färben betrifft, so erinnere ich mich an diese beiden Threads:

ListView Zeilen färben
ListView bestimmte Zeilen färben

Die Virtualisierung einer ListView zeigt diese Demo: klick

Centrii 9. Apr 2008 07:41

Re: Listview Zeilen färben, On Custom DrawItem
 
danke für die Links...

Ich zieh mich jetzt mal zurück und versuch mein Projekt auf eine virtuelle Listview umzubauen. Das wird ein wenig dauern :cry:

Danke Marabu

Centrii 11. Apr 2008 06:05

Re: Listview Zeilen färben, On Custom DrawItem / Drag N´Drop
 
so, jetzt hab ich meine ListView in den VirtualMode umgestellt. Alles geht wieder, nur mit einem hab ich noch ein Problem.
Mein Drag N´Drop von früher geht ja jetzt auch nicht mehr und ich bin grad am grübeln wie ich das jetzt mit der VirtualMode
Listview mache.
Bisher machte ich es so...

Delphi-Quellcode:
procedure TfDLMain.ListViewDragDrop(Sender, Source: TObject; X, Y: Integer);
var
DragItem, DropItem, CurrentItem, NextItem: TListItem;
begin
  if Sender = Source then
  with TListView(Sender) do begin
   DropItem := GetItemAt(X, Y);
   CurrentItem := Selected;
   while CurrentItem <> nil do begin
   NextItem := GetNextItem(CurrentItem, SdAll, [IsSelected]);
   if DropItem = nil then DragItem := Items.Add
   else
     DragItem := Items.Insert(DropItem.Index);
     DragItem.Assign(CurrentItem);
     CurrentItem.Free;
     CurrentItem := NextItem;
   end;
  end;
end;

//**********************************************************************************************************************

procedure TfDLMain.ListViewDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
 Accept := Sender = ListView;
end;
jetzt frage ich mich wie ich das jetzt machen kann. Hat da jemand ne Idee?
Ich hab eine Values : TStringlist wie in dem Demo vom Marabu.

Gruß Ruben

marabu 11. Apr 2008 07:31

Re: Listview Zeilen färben, On Custom DrawItem
 
Moin Ruben,

eigentlich ist es sehr einfach: In deinem event handler ermittelst du nur noch die Index-Werte der betroffenen Items, das Verschieben erledigst du auf der StringList, in der du deine Daten verwaltest.

Freundliche Grüße

Centrii 11. Apr 2008 09:08

Re: Listview Zeilen färben, On Custom DrawItem
 
Wieder Danke Marabu, eigentlich hätte ich da auch selber drauf kommen können :oops:

trotzdem muss ich dich nochmal nerven,
ich hab das jetzt mal geändert wie ich gedacht habe, funktioniert für ein Item auch
wunderbar, nur beim Multiselect gibts Probleme.

Delphi-Quellcode:
procedure TfDLMain.ListViewDragDrop(Sender, Source: TObject; X, Y: Integer);
var
DragItem, DropItem, CurrentItem, NextItem: TListItem;
i, Index1, Index2 :Integer;
begin
  if Sender = Source then begin
   for i:= 0 to ListItems.Count-1 do begin
     if ListItems[i].Selected = true then begin
       DropItem := ListView.GetItemAt(X, Y);
       Index1 := i;
       Index2 := DropItem.Index;
       Values.Insert(Index2,Values[Index1]);
       Values.Delete(Index1);
     end;
     end;
   end;
  ListView.Invalidate;

//*************************************************************************
//*****   alte Methode fuer Listview ohne VirtualMode ********************
//*************************************************************************
//  if Sender = Source then
//  with TListView(Sender) do begin
//   DropItem := GetItemAt(X, Y);
//   CurrentItem := Selected;
//   while CurrentItem <> nil do begin
//   NextItem := GetNextItem(CurrentItem, SdAll, [IsSelected]);
//   if DropItem = nil then DragItem := Items.Add
//   else
//     DragItem := Items.Insert(DropItem.Index);
//     DragItem.Assign(CurrentItem);
//     CurrentItem.Free;
//     CurrentItem := NextItem;
//   end;
//  end;
//*************************************************************************
//*************************************************************************

end;
hab das Problem, dass er zwar die Items verschiebt, aber dann nur ein Item aus meiner "Values" löscht.

Gruß Ruben


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:02 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz