![]() |
ListView mit OwnerData schneller machen?
Hallo,
ich habe eine ListView, die mit der Zunahme der Daten total langsamer wird. Nun habe ich gelesen, dass man mit OwnerData sozusagen eine virtuelle LV machen kann und die Daten im Ereignis OnData lädt. Nun lade ich die Daten wie folgt in die LV, wie mache ich das jetzt mit OnData? Ich fülle die LV noch an anderen Stellen, muss auch das in die OnData? Irgendwie verstehe ich das ganze nicht so richtig. Danke!
Delphi-Quellcode:
procedure TForm1.ShowMedia();
var dbFile: String; db: TSQLiteDatabase; tb: TSQLIteTable; MyItem: TListItem; s: String; begin // ListView Eintraege loeschen MediaListView.Clear; EntleiherListView.Clear; dbFile := ExtractFilePath(ParamStr(0)) + 'Database.db'; db := TSQLiteDatabase.Create(dbFile); try // Datensaetze der media Tabelle einlesen tb := db.GetTable('SELECT media.id_media,' + 'media.mediatitle, ' + 'media.description,' + 'place.planame, ' + 'mediatype.mtypename, ' + 'category.catname, ' + 'entleiher.elastname, ' + 'entleiher.efirstname, ' + 'author.aname ' + 'FROM media ' + 'LEFT JOIN place ON media.fk_place_id=place.id_place ' + 'LEFT JOIN mediatype ON media.fk_mediatype_id=mediatype.id_mediatype ' + 'LEFT JOIN category ON media.fk_category_id=category.id_category ' + 'LEFT JOIN language ON media.fk_language_id=language.id_language ' + 'LEFT JOIN author ON media.fk_author_id=author.id_author ' + 'LEFT JOIN entleiher ON media.fk_entleiher_id=entleiher.id_entleiher ORDER BY media.mediatitle ASC'); try // Alle Datensaetze in die ListView einlesen if tb.Count > 0 then begin while not tb.EOF do begin MyItem := MediaListView.Items.Add; MyItem.Data := Pointer(tb.FieldAsInteger(tb.FieldIndex['id_media'])); //data mit ids fuellen MyItem.Caption := tb.FieldAsString(tb.FieldIndex['mediatitle']); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['aname'])); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['description'])); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['mtypename'])); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['catname'])); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['planame'])); MyItem.SubItems.Add(tb.FieldAsString(tb.FieldIndex['elastname']) + ' ' + tb.FieldAsString(tb.FieldIndex['efirstname'])); tb.Next; end; end; finally tb.Free; end; finally db.Free; end; // Anzahl der Datensaetze anzeigen ShowListCount(); end; |
AW: ListView mit OwnerData schneller machen?
Warum verwendest du denn kein TDBGrid?
Das DBGrid macht im Prinzip nichts anderes als dein Dataset (TSQLIteTable) in einen speziellen Status (dsBlockRead) zu versetzen und so viele Zeilen auszulesen wie gerade angezeigt werden müssen. |
AW: ListView mit OwnerData schneller machen?
Jah... ich möchte ohne Delphi-Komponenten auskommen.
|
AW: ListView mit OwnerData schneller machen?
Was ziemlich viel bringt ist Begin/EndUpdate
Delphi-Quellcode:
MediaListView.Items.BeginUpdate;
try MediaListView.Items.Clear; .. finally MediaListView.Items.EndUpdate; end; |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Verwende doch den virtuellen Modus der TListView.
|
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Ich werde alt und grenzdebil. Entschuldige.
|
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Ich hab zwar schon früher mit ListView gearbeitet, aber letzte Woche zum erstem mal mit paar tausend Daten. Meine Erfahrung waren die: ich hab einen Ordner mit etwa 3000 Daten geladen (zuerst alle wichtigen Daten in eine Liste mit Objekten). Der Aufbau der LV hat fast 10 Sekunden gedauert. Nachdem ist es etwas optimiert habe waren es immer noch 5 Sekunden. Natürlich war das nicht akzeptabel, also habe ich ganz anders gemacht.
Zuerst wurde pro Datei ein Item erstellt und nur das Caption gefüllt, inkl. Grund-Icon (leeres Dokument-Icon). Das dauerte 50 ms. Erst im zweiten Schritt wurden die anderen Infos eingespielt, aber eben nicht alles auf einmal, es wurde nur immer der Teil von LV aktualisiert, der sichtbar war. Der Vorgang dauerte etwas über 100 ms. Wurde LV gescrollt, wurde der Teil aktualisiert. Da die Daten im Objekt am Item sind, spielt es keine Rolle ob LV komplett gefüllt ist. Wenn dir die Methode nicht gefällt, im Demo-Ordner von Delphi (zumindest in Delphi 7) ist ein tolles Beispiel zu LV ("Virtual Listview"), aber etwas kompliziert. Dafür aber sehr schnell, noch schneller als meine Lösung. |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Ich muss erst gucken ob ich es noch habe. Ich hab es einfach als Übung gesehen, da speichere ich die Ergebnisse nicht immer. Selbst wenn, es war etwas chaotisch, da ich vieles auf ein mal getestet habe. Ich gucke mal aber mein Tempordner ob ich was finde, wenn ja, melde ich mich.
|
AW: ListView mit OwnerData schneller machen?
Zitat:
![]() |
AW: ListView mit OwnerData schneller machen?
TVirtualTreeView funktioniert sehr gut auch mit großen Datenmengen.
|
AW: ListView mit OwnerData schneller machen?
Das Grundprinzip beim OwnerDraw / Virtual ist, dass die Daten in einer Struktur unabhängig vom Control abgelegt werden.
Das Control bekommt bei einer Änderung nur noch mitgeteilt, dass sich die Anzahl der Einträge geändert haben (ruft implizit
Delphi-Quellcode:
auf) oder dass sich einfach nur der Inhalt geändert hat (expliziter Aufruf von
Invalidate
Delphi-Quellcode:
).
Invalidate
Beim ListView mit
Delphi-Quellcode:
sollte zwingend
OwnerDraw
Delphi-Quellcode:
eingeschaltet werden, dass gibt sonst ganz hässliche Effekte (enfach mal ohne ausprobieren, will man danach nicht mehr haben).
DoubleBuffered
Kleiner Profi-Tipp (habe ich mal aufgeschnappt): Eine Basis-Form von der alle Forms des Projekts abgeleitet werden prüft ob es dort ein ListView-Control mit OwnerDraw gibt und schaltet automatisch DoubleBuffered ein. Dann kann man das vergessen, weil man es nicht mehr vergisst ;) |
AW: ListView mit OwnerData schneller machen?
Liste der Anhänge anzeigen (Anzahl: 1)
Also ich konnte das alte Beispiel nicht finden, deshalb habe ich auf die Schnelle etwas zusammengebastelt. Also bitte nicht zu kritisch sein, ist nur eine Übung. Auch habe ich alles in ein Ereignis gepackt, damit es schneller geht. Das Prinzip sollte aber erkennbar sein, zuerst wird alles in eine Liste geladen, dann an LV übergeben, zuletzt im Ereignis vervollständigt.
EDIT: Ich bin den Code noch mal durchgegangen und paar Fehler entdeckt, so werden einige Werte nicht in Data gespeichert, aber es funktioniert trotz dem. |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
popov, ich habe dein beispiel mal ausprobiert. auf die art un weise kann ich das Item.ImageIndex := ImageList.AddIcon(FileIcon); in DrawSubItem der ListView verlegen.
mein vorgang dauert zwar noch immer 4 sekunden (besser als +20 vorher) aber in der zeile "Item.ImageIndex := ImageList.AddIcon(FileIcon);" sagt delphi mir dass die "bildgröße nicht gültig/korrekt" wäre. problem hat sich erledigt. statt ImageList musste ich ImageList1 einsetzen. frage: ist das dein persönlicher stil da noch vorher
Delphi-Quellcode:
zu machen oder hat das einen zweck?
ListView := TListView(Sender);
ImageList := TImageList(ListView.SmallImages); denn ich verwende einfach ImageList1 (bei mir gibt es nur eine). |
AW: ListView mit OwnerData schneller machen?
Das hat weniger mit Stil zu tun. Ich kann zwar den Fehler nicht erkennen, aber wie gesagt, es war schnell erstellt. Im Grunde ist es egal ob man
Delphi-Quellcode:
oder
ListView1
Delphi-Quellcode:
nutzt, aber, vorausgesetzt der Sender ist ListView1, brauche ich den Namen nicht, sondern hole mir den lokal. Der Vorteil, ich kann irgendwann ListViews1 umbenennen, ohne das auch ich Code machen zu müssen. Das gleiche gibt für
ListView := TListView(Sender);
Delphi-Quellcode:
. Auch im SmallImages sollte die ImageList stehen, vorausgesetzt sie wurde eingetragen. Warum also auf die Komponente per Namen zugreifen, ich hole mir die Komponente lokal.
ImageList := TImageList(ListView.SmallImages);
Ob das nun richtig ist oder falsch, keine Ahnung, ich sehe Vorteile drin. Bei Bedarf kann ich mir aus einem anderen Programm den Code kopieren ohne ihn ändern zu müssen. Dann gibt es noch die Möglichkeit deine SystemListe zu nutzen, das habe ich aber auch noch nicht ganz raus. @d7user1 Ich hab gerade dein andern Thread: ![]() So wie das Beispiel (oben) steht ist es nicht optimal, aber die Frage war nicht darum optimal zu sein, sondern eine menge Items schnell anzuzeigen. Das andere Problem spielte keine Rolle, also habe ich es im Beispiel gelassen. Es geht drum, dass wenn du 13.000 Dateien mit Icons liest, du auch 13.000 Icons in ImageList speicherst. Das ist eigentlich nicht nötig, denn viele Icons wiederholen sich. Also warum das gleiche Icon immer und immer wieder speichern? Die Lösung ist iIcon, u. U. auch szDisplayName (das habe ich noch nicht ganz geprüft). Zumindest bekommt man bei iIcon eine Zahl die anscheinend Typisch für ein Icon ist. Somit muss prüfen ob das Icon in der ImageList bereits drin ist, wenn ja, einfach nur auf dieses Icon verweisen. |
AW: ListView mit OwnerData schneller machen?
hier ist ein beispiel zu iIcon aber es funktionier nicht mit iner ListView (vorher war überall ComboBoxEx):
Delphi-Quellcode:
procedure DisplayDrivesEx(aListView: TListView);
var i, j: Integer; vItem: TListItem; vFileInfo: TSHFileInfo; vImgList: THandle; s, D: string; sl: TStringList; begin sl := TStringList.Create; sl.Add('C:\'); sl.Add('D:\'); sl.Add('E:\'); sl.Add('D:\TestDatei.exe'); try aListView.Items.BeginUpdate; aListView.Items.Clear; vImgList := SHGetFileInfo(PChar(sl[0]), 0, vFileInfo, SizeOf(vFileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON); SendMessage(aListView.Handle, CBEM_SETIMAGELIST, 0, vImgList); DestroyIcon(vFileInfo.hIcon); for i := 0 to sl.Count - 1 do begin SHGetFileInfo(PChar(sl[i]), 0, vFileInfo, SizeOf(vFileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_DISPLAYNAME); vItem := aListView.Items.Add; vItem.ImageIndex := vFileInfo.iIcon; end; finally aListView.Items.EndUpdate; end; sl.Free; end; |
AW: ListView mit OwnerData schneller machen?
Siehe hier...
Delphi-Quellcode:
MediaListView.Items.BeginUpdate;
try MediaListView.Items.Clear; .. finally MediaListView.Items.EndUpdate; end; Zitat:
Zitat:
|
AW: ListView mit OwnerData schneller machen?
ich habe jetzt nach einiger zeit eine funktionierende und gute lösung die system-images zu nutzen: (wir holen nur kleine icons)
man braucht ein TListView und ein TImageList.im OI keine änderungen treffen. für ListView Data wird deklariert:
Delphi-Quellcode:
folgendes wird z.b. private in der unit wo die listview deklariert:
type
TMeineDaten = class aFilename: String; bIsUpdated: Boolean; end;
Delphi-Quellcode:
folgendes wird im OnCreate der unit geschrieben:
hImgSm: HIMAGELIST; // uses CommCtrl
aFileIcon: TSHFileInfo; // uses ShellAPI
Delphi-Quellcode:
und folgendes im CustomDrawSubItem der ListView:
hImgSm := HIMAGELIST(SHGetFileInfo('', 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_SMALLICON));
if (hImgSm <> 0) then ImageList1.Handle := hImgSm; ImageList1.ShareImages := True; ListView1.SmallImages := ImageList1;
Delphi-Quellcode:
Item zur ListView hinzufügen:
if (Item = nil) then
Exit; if not TMeineDaten(Item.Data).bIsUpdated then begin ZeroMemory(@aFileIcon, SizeOf(aFileIcon)); SHGetFileInfo(PChar(TMeineDaten(Item.Data).aFilename), 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_SMALLICON); Item.ImageIndex := aFileIcon.iIcon; TMeineDaten(Item.Data).bIsUpdated := True; end;
Delphi-Quellcode:
var
aIem: TListItem; aMeineDaten: TMeineDaten; begin aMeineDaten:= TMeineDaten.Create; aMeineDaten.aFilename := 'C:\meineDatei.exe'; aMeineDaten.bIsUpdated := False; aItem := ListView1.Items.Add; aItem.Caption := 'meineDatei.exe'; aItem.SubItems.Add('meineDatei SubItem'); aItem.Data := aMeineDaten; |
AW: ListView mit OwnerData schneller machen?
Zitat:
Damit aber mein Beispiel damit funktioniert (aber wie gesagt, ohne Gewähr) muss es so geändert werden:
Delphi-Quellcode:
Ob es richtig ist, weiß ich noch nicht, es funktioniert aber.
implementation
... var sfiTest: TSHFILEINFO; //***NEU procedure TForm1.FormCreate(Sender: TObject); ... begin ... SmallImages := ImageList1; ImageList1.Handle := SHGetFileInfo('C:\', 0, sfiTest, SizeOf(sfiTest), SHGFI_SYSICONINDEX or SHGFI_SMALLICON); //***NEU ... end; function GetFileTypeNameAndIcon3(const FileName: String; //***Andere Funktion out FileTypeName: String; out IconIndex: Integer): Boolean; var sfi: TSHFILEINFO; begin Result := SHGetFileInfo(PChar(FileName), 0, sfi, SizeOf(sfi), SHGFI_TYPENAME or SHGFI_ICON or SHGFI_SMALLICON) <> 0; if Result then begin FileTypeName := sfi.szTypeName; IconIndex := sfi.iIcon; //iIcon und nicht hIcon end; end; procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); var ... FileIconIndex: Integer; ... begin ... if not FileInfoEx2.IsUpToDate then //***Änderung begin with FileInfoEx2 do GetFileTypeNameAndIcon3(Path + Name, FileTypeName, FileIconIndex); Item.SubItems[1] := FileTypeName; Item.ImageIndex := FileIconIndex; FileInfoEx2.IsUpToDate := True; end; ... end; |
AW: ListView mit OwnerData schneller machen?
Zitat:
Du kannst eine Komponente verwenden die genau für die Aufgabe entwickelt wurde (DBGrid). Du kannst aber auch eine nicht-datensentive Komponente (ListView) verwenden und durch zusätzlichen Code an das Dataset anbinden. Man sollte aber dabei nie das ![]() Ein DBGrid ist innerhalb von 15 Sekunden Programmierzeit an ein Dataset angebunden. Um ein (virtuelles) ListView an ein Dataset anzubinden benötigt man ca einen Tag Programmierzeit. Lohnt sich das? |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Guck mal dbExpress an.
Edit: Evtl. erst ab Delphi XE3. |
AW: ListView mit OwnerData schneller machen?
Zitat:
Eine TDatasource Komponente auf das Formular platzieren und im
Delphi-Quellcode:
deine SQLite-Komponente auswählen.
Property Dataset
Dann ein DBGrid auf's Formular und das
Delphi-Quellcode:
setzen.
Property DataSource
Du brauchst keine einzige Zeile Sourcecode sondern kannst alles über den Objektinspektor einstellen. Man kann sogar die Tabelle oder Query zur Entwicklungszeit aktiv schalten und sieht dann im DBGrid die Daten. |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Zitat:
Damit können die datensensitiven Komponenten nicht angebunden werden. Für kleine Projekte kann man sich auch so behelfen aber wenn's etwas mehr wird (> 3 Tabellen) braucht man "richtige" Komponenten. |
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
Liste der Anhänge anzeigen (Anzahl: 2)
Weil das mit den Generics und Anonymen Methoden so schön geht, habe ich hier mal eine kleine Virtual-ListView Demo gemacht.
Vom Start weg erzeugt die 100.000 zufällige Personen, die dann noch bearbeitet/gelöscht/hinzugefügt werden können. Der größte Zeitfresser ist hier die Sortierung, was aber auch nichts macht, da ich die Aktionen (anlegen, speichern, sortieren) im Hintergrund ausführen lasse und der Anwender so lange eine modale Form angezeigt bekommt, damit dem nicht langweilig wird ;) Evtl. kann das hier ja als Anregung dienen. Achtung: Das Beispiel ist nur unter den aktuelleren Delphis (ab XE3?) lauffähig (im Anhang befindet sich auch eine kompilierte Version) Haupt-Form:
Delphi-Quellcode:
unit UI_Form_Main;
interface uses Winapi.Windows, Winapi.Messages, System.Generics.Collections, System.Actions, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ActnList, Vcl.ExtCtrls, UI_Form_Base, Model_Person; type TMainForm = class( TBaseForm ) Persons_ListView : TListView; NewPerson_Button : TButton; EditPerson_Button : TButton; ActionList1 : TActionList; NewPerson_Action : TAction; EditPerson_Action : TAction; Action_Panel : TPanel; DeletePerson_Action : TAction; DeletePerson_Button : TButton; procedure Persons_ListViewData( Sender : TObject; Item : TListItem ); procedure Persons_ListViewEdited( Sender : TObject; Item : TListItem; var S : string ); procedure Persons_ListViewChange( Sender : TObject; Item : TListItem; Change : TItemChange ); procedure NewPerson_ActionExecute( Sender : TObject ); procedure EditPerson_ActionExecute( Sender : TObject ); procedure EditPerson_ActionUpdate( Sender : TObject ); procedure DeletePerson_ActionUpdate( Sender : TObject ); procedure DeletePerson_ActionExecute( Sender : TObject ); private { Person-ID Generator } FNextPersonId : Integer; function GetNextPersonId : Integer; private { Model } FPersons : TList<TPerson>; FCurrentPersonIndex : Integer; function GetCurrentPerson : TPerson; procedure SetCurrentPerson( const Value : TPerson ); protected { Binding } procedure DoLoadFromModel; override; procedure DoSaveToModel; override; private { Background } procedure DoCreateSomePersons( Count : Integer ); procedure DoSave( Person : TPerson ); procedure DoSort; private { Facade Methods } function EditPerson( Person : TPerson ) : TPerson; procedure CreateSomePersons( Count : Integer ); procedure SaveAndSort( Person : TPerson ); public { Facade } procedure AddNewPerson; procedure EditCurrentPerson; procedure DeleteCurrentPerson; public procedure AfterConstruction; override; procedure BeforeDestruction; override; public property CurrentPerson : TPerson read GetCurrentPerson write SetCurrentPerson; end; var MainForm : TMainForm; implementation {$R *.dfm} uses System.DateUtils, UI_Form_Person_Edit, UI_Form_BackgroundWorker; { TMainForm } procedure TMainForm.AddNewPerson; begin CreateSomePersons( 1 ); LoadFromModel; end; procedure TMainForm.AfterConstruction; begin inherited; FPersons := TObjectList<TPerson>.Create( TPerson.EqualityComparer ); FCurrentPersonIndex := FPersons.Count - 1; CreateSomePersons( 100000 ); LoadFromModel; end; procedure TMainForm.BeforeDestruction; begin inherited; FPersons.Free; end; procedure TMainForm.NewPerson_ActionExecute( Sender : TObject ); begin inherited; AddNewPerson; end; function TMainForm.EditPerson( Person : TPerson ) : TPerson; var LPersonEdit : TEditPersonForm; begin if Assigned( Person ) then begin LPersonEdit := TEditPersonForm.Create( nil ); try LPersonEdit.Person := Person; if LPersonEdit.ShowModal = mrOk then begin SaveAndSort( LPersonEdit.Person ); end; finally LPersonEdit.Free; end; end; Result := Person; end; procedure TMainForm.EditPerson_ActionExecute( Sender : TObject ); begin inherited; EditCurrentPerson; end; procedure TMainForm.EditPerson_ActionUpdate( Sender : TObject ); begin inherited; ( Sender as TAction ).Enabled := Assigned( CurrentPerson ); end; procedure TMainForm.CreateSomePersons( Count : Integer ); var LPerson : TPerson; begin DoCreateSomePersons( Count ); LPerson := FPersons.Last; DoSort; CurrentPerson := LPerson; end; procedure TMainForm.DeleteCurrentPerson; begin if Assigned( CurrentPerson ) then begin FPersons.Remove( CurrentPerson ); Dec( FCurrentPersonIndex ); end; LoadFromModel; end; procedure TMainForm.DeletePerson_ActionExecute( Sender : TObject ); begin inherited; DeleteCurrentPerson; end; procedure TMainForm.DeletePerson_ActionUpdate( Sender : TObject ); begin inherited; ( Sender as TAction ).Enabled := Assigned( CurrentPerson ); end; procedure TMainForm.DoCreateSomePersons( Count : Integer ); begin PerformInBackground( procedure var LPerson : TPerson; LIdx : Integer; begin for LIdx := 1 to Count do begin LPerson := TPerson.Create( GetNextPersonId ); try LPerson.Firstname := C_FIRSTNAMES[Random( Length( C_FIRSTNAMES ) )]; LPerson.Lastname := C_LASTNAMES[Random( Length( C_LASTNAMES ) )]; LPerson.DisplayAs := LPerson.Lastname + ', ' + LPerson.Firstname; LPerson.DOB := Date - ( Random( 365 * 60 ) + 18 * 365 ); FPersons.Add( TPerson.Create( LPerson ) ); finally LPerson.Free; end; end; end, Format( 'Erzeuge %d Einträge...', [Count] ) ); end; procedure TMainForm.DoLoadFromModel; begin inherited; // Anzahl der Einträge festlegen Persons_ListView.Items.Count := FPersons.Count; // Aktuelle Auswahl festlegen Persons_ListView.ItemIndex := FCurrentPersonIndex; // sieht komisch aus, ist aber notwendig damit der aktuelle Eintrag auch // sichtbar wird Persons_ListView.Items.Count := FPersons.Count; // Falls Änderungen an den Daten vorgenommen wurden, einfach mal neuzeichnen lassen Persons_ListView.Invalidate; end; procedure TMainForm.DoSave( Person : TPerson ); begin PerformInBackground( procedure begin if FPersons.Contains( Person ) then FPersons[FPersons.IndexOf( Person )].Assign( Person ) else FPersons.Add( TPerson.Create( Person ) ); end, Format( 'Speichern von %s', [Person.ToString] ) ); end; procedure TMainForm.DoSaveToModel; begin inherited; FCurrentPersonIndex := Persons_ListView.ItemIndex; end; procedure TMainForm.DoSort; begin PerformInBackground( procedure begin FPersons.Sort( TPerson.SortComparer ); end, Format( 'Sortiere %d Einträge...', [FPersons.Count] ) ); end; procedure TMainForm.EditCurrentPerson; begin CurrentPerson := EditPerson( CurrentPerson ); LoadFromModel; end; function TMainForm.GetCurrentPerson : TPerson; begin if FCurrentPersonIndex < 0 then Result := nil else Result := FPersons[FCurrentPersonIndex]; end; function TMainForm.GetNextPersonId : Integer; begin Result := FNextPersonId; Inc( FNextPersonId ); end; procedure TMainForm.Persons_ListViewChange( Sender : TObject; Item : TListItem; Change : TItemChange ); begin inherited; SyncWithModel; end; procedure TMainForm.Persons_ListViewData( Sender : TObject; Item : TListItem ); var LPerson : TPerson; begin inherited; LPerson := FPersons[Item.Index]; Item.Caption := LPerson.ToString; Item.SubItems.Add( LPerson.Lastname ); Item.SubItems.Add( LPerson.Firstname ); Item.SubItems.Add( DateToStr( LPerson.DOB ) ); Item.SubItems.Add( IntToStr( YearsBetween( Date, LPerson.DOB ) ) ); end; procedure TMainForm.Persons_ListViewEdited( Sender : TObject; Item : TListItem; var S : string ); var LPerson : TPerson; begin inherited; LPerson := TPerson.Create( FPersons[Item.Index] ); try if LPerson.DisplayAs <> S then begin LPerson.DisplayAs := S; EditPerson( LPerson ); CurrentPerson := LPerson; end; finally LPerson.Free; end; end; procedure TMainForm.SaveAndSort( Person : TPerson ); begin DoSave( Person ); DoSort; end; procedure TMainForm.SetCurrentPerson( const Value : TPerson ); begin if not Assigned( Value ) then FCurrentPersonIndex := - 1 else FCurrentPersonIndex := FPersons.IndexOf( Value ); LoadFromModel; end; end. |
AW: ListView mit OwnerData schneller machen?
Ich bekomme eine Warnung "Behav_214-Trojaner" bei der Zip-Datei.
|
AW: ListView mit OwnerData schneller machen?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
|
AW: ListView mit OwnerData schneller machen?
SonicWALL Gateway Anti-Virus Service. Ich komm da hier nicht ran.
|
AW: ListView mit OwnerData schneller machen?
Zitat:
|
AW: ListView mit OwnerData schneller machen?
|
AW: ListView mit OwnerData schneller machen?
Sonic Wall auch nicht mehr.
Danke! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:40 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz