AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Auf Änderungen in einer TObjectList<T> reagieren
Thema durchsuchen
Ansicht
Themen-Optionen

Auf Änderungen in einer TObjectList<T> reagieren

Ein Thema von RWarnecke · begonnen am 19. Jun 2011 · letzter Beitrag vom 25. Jun 2011
Antwort Antwort
Benutzerbild von RWarnecke
RWarnecke

Registriert seit: 31. Dez 2004
Ort: Stuttgart
4.408 Beiträge
 
Delphi XE8 Enterprise
 
#1

Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 10:14
Delphi-Version: 2010
Hallo zusammen,

in diesem Beitrag wurde ich darauf aufmerksam gemacht, warum ich die TObjectList nicht durch eine TObjectList<T> ersetze und mit Generics arbeite. Ich habe mir einige Tutorials durchgelesen und folgendes mal zusammengebaut :
Delphi-Quellcode:
type
  TModifyActionList = (lnNone, lnChange, lnDelete);
  TZahlungsart = class
  private
    FOnChange : TNotifyEvent;
    FModifyAction : TModifyActionList;
    FID : Integer;
    FZahlungsart : string;
    procedure SetID(Value: Integer);
    procedure SetZahlungsart(Value: string);
  public
    property ID : Integer read FID write SetID;
    property Zahlungsart : string read FZahlungsart write SetZahlungsart;
    property ModifyAction : TModifyActionList read FModifyAction write FModifyAction;
    property OnChange : TNotifyEvent read FOnChange write FOnChange;
  end;

var
  ZahlungsartList : TObjectList<TZahlungsart>;
  Zahlungsart: TZahlungsart;
  CounterDB: Integer;

procedure TForm3.Btn_1Click(Sender: TObject);
begin
  CounterDB := 0;
  L_1.Caption := 'Anzahl der Objekte in der Liste :' + IntToStr(ZahlungsartList.Count);
  Edt_1.Text := IntToStr(ZahlungsartList.Items[CounterDB].ID);
  Edt_2.Text := ZahlungsartList.Items[CounterDB].Zahlungsart;
end;

procedure TForm3.Edt_2Exit(Sender: TObject);
begin
  ZahlungsartList.Items[CounterDB].ModifyAction := lnChange;
  ZahlungsartList.Items[CounterDB].Zahlungsart := Edt_2.Text;
  ZahlungsartList.Items[CounterDB].ModifyAction := lnNone;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  ZahlungsartList := TObjectList<TZahlungsart>.Create;
  if not UniCon_1.Connected then
    UniCon_1.Connect;
  with UniQuery_1 do
  begin
    SQL.Text := 'SELECT * FROM Zahlungsarten;';
    Open;
    while not Eof do
    begin
      Zahlungsart := TZahlungsart.Create;
      Zahlungsart.OnChange := ZahlungsartChange;
      Zahlungsart.ID := FieldByName('ID').AsInteger;
      Zahlungsart.Zahlungsart := FieldByName('Zahlungsart').AsString;
      ZahlungsartList.Add(Zahlungsart);
      Next;
    end;
    Close;
  end;
end;

procedure TForm3.SBtn_1Click(Sender: TObject);
begin
  CounterDB := CounterDB - 1;
  Edt_1.Text := IntToStr(ZahlungsartList.Items[CounterDB].ID);
  Edt_2.Text := ZahlungsartList.Items[CounterDB].Zahlungsart;
end;

procedure TForm3.SBtn_2Click(Sender: TObject);
begin
  CounterDB := CounterDB + 1;
  Edt_1.Text := IntToStr(ZahlungsartList.Items[CounterDB].ID);
  Edt_2.Text := ZahlungsartList.Items[CounterDB].Zahlungsart;
end;

procedure TForm3.ZahlungsartChange;
begin
  with UniQuery_1 do
  begin
    SQL.Text := 'UPDATE OR INSERT INTO Zahlungsarten (ID, Zahlungsart) VALUES (:ID, :Zahlungsart) MATCHING (ID);';
    ParamByName('ID').AsInteger := ZahlungsartList.Items[CounterDB].ID;
    ParamByName('Zahlungsart').AsString := ZahlungsartList.Items[CounterDB].Zahlungsart;
    Execute;
  end;
end;

{ TZahlungsart }

procedure TZahlungsart.SetID(Value: Integer);
begin
  FID := Value;
  if (Assigned(FOnChange)) and (FModifyAction = lnChange) then
    FOnChange(Self);
end;

procedure TZahlungsart.SetZahlungsart(Value: string);
begin
  FZahlungsart := Value;
  if (Assigned(FOnChange)) and (FModifyAction = lnChange) then
    FOnChange(Self);
end;
Da ich noch am Anfang stehe mit Generics, habe ich noch Fragen :

1.) Ist das soweit schon mal richtig oder gibt es da noch Verbesserungen ? Wenn ja, was kann man im allgemeinen verbessern und auch in Bezug auf mehrere TObjectList<TKlassenname>.Create's ?
2.) Wie realisiere ich es, dass das OnChange-Event bei neuen Datensätzen ausgelöst wird ?
3.) In meiner alten Konstelation hatte ich noch eine extra Procedure für das Löschen eines Datensatzes, wie mache ich das hier in diesem Beispiel ?
Rolf Warnecke
App4Mission
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.995 Beiträge
 
Delphi 12 Athens
 
#2

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 12:22
1.) Ist das soweit schon mal richtig oder gibt es da noch Verbesserungen ? Wenn ja, was kann man im allgemeinen verbessern und auch in Bezug auf mehrere TObjectList<TKlassenname>.Create's ?
Du solltest einen neuen Typ TZahlungsartList = TObjectList<TZahlungsart>; deklarieren.

2.) Wie realisiere ich es, dass das OnChange-Event bei neuen Datensätzen ausgelöst wird ?
Überschreibe in TZahlungsartList die Methode Notify, dann kannst du auf die verschiedenen Ereignisse reagieren. Das gilt übrigens auch für den nicht-generischen Ansatz.

3.) In meiner alten Konstelation hatte ich noch eine extra Procedure für das Löschen eines Datensatzes, wie mache ich das hier in diesem Beispiel ?
Wie hast du es bisher gemacht?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von RWarnecke
RWarnecke

Registriert seit: 31. Dez 2004
Ort: Stuttgart
4.408 Beiträge
 
Delphi XE8 Enterprise
 
#3

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 13:21
1.) Ist das soweit schon mal richtig oder gibt es da noch Verbesserungen ? Wenn ja, was kann man im allgemeinen verbessern und auch in Bezug auf mehrere TObjectList<TKlassenname>.Create's ?
Du solltest einen neuen Typ TZahlungsartList = TObjectList<TZahlungsart>; deklarieren.
In wie weit soll mir das helfen ?

2.) Wie realisiere ich es, dass das OnChange-Event bei neuen Datensätzen ausgelöst wird ?
Überschreibe in TZahlungsartList die Methode Notify, dann kannst du auf die verschiedenen Ereignisse reagieren. Das gilt übrigens auch für den nicht-generischen Ansatz.
Das heißt also ich kann die TObjectList<TZahlungsart> genauso behandeln wie eine nicht generische ObjectList ?

3.) In meiner alten Konstelation hatte ich noch eine extra Procedure für das Löschen eines Datensatzes, wie mache ich das hier in diesem Beispiel ?
Wie hast du es bisher gemacht?
Ich habe das bis jetzt folgendermaßen gemacht :
Delphi-Quellcode:
  TZahlungsartObjListe = class(TObjectList)
  private
    FOnChange : TZahlungsartListeAddEvent;
    FModifyAction : TModifyActionList;
    FNewRecord : Boolean;
    procedure DeleteRecord(Klasse: TZahlungsart);
  protected
    function getItem(Index: Integer): TZahlungsart; virtual;
    procedure setItem(Index: Integer; Objekt: TZahlungsart); virtual;
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  public
    function Add(Objekt: TZahlungsart): Integer; virtual;
    function NewRecord(Objekt: TZahlungsart): Integer; virtual;
    function Remove(Objekt: TZahlungsart): Integer; virtual;
    function IndexOf(Objekt: TZahlungsart): Integer; virtual;
    procedure Insert(Index: Integer; Objekt: TZahlungsart); virtual;
    property Items[index: Integer]: TZahlungsart read getItem write setItem; default;
    property ModifyAction : TModifyActionList read FModifyAction write FModifyAction;
    property OnChange: TZahlungsartListeAddEvent read FOnChange write FOnChange;
  end;

{ TZahlungsartObjListe }

function TZahlungsartObjListe.Add(Objekt: TZahlungsart): Integer;
begin
  FNewRecord := False;
  Result := inherited Add(Objekt);
end;

procedure TZahlungsartObjListe.DeleteRecord(Klasse: TZahlungsart);
begin
  with DM_Main.UniQuery_Zahlungsart do
  begin
    SQL.Text := 'DELETE FROM Zahlungsarten WHERE ID = :ID AND Zahlungsart = :Zahlungsart;';
    ParamByName('ID').AsInteger := Klasse.FID;
    ParamByName('Zahlungsart').AsString := Klasse.FZahlungsart;
    Execute;
  end;
end;

function TZahlungsartObjListe.getItem(Index: Integer): TZahlungsart;
begin
  Result := TZahlungsart(inherited Items[Index]);
end;

function TZahlungsartObjListe.IndexOf(Objekt: TZahlungsart): Integer;
begin
  Result := inherited IndexOf(Objekt);
end;

procedure TZahlungsartObjListe.Insert(Index: Integer;
  Objekt: TZahlungsart);
begin
  inherited Insert(Index, Objekt);
end;

function TZahlungsartObjListe.NewRecord(Objekt: TZahlungsart): Integer;
begin
  FNewRecord := True;
  Result := inherited Add(Objekt);
end;

procedure TZahlungsartObjListe.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if (Assigned(FOnChange)) and (FNewRecord) and (Action <> lnDeleted) then
  begin
    FNewRecord := False;
    FOnChange(Self, TZahlungsart(Ptr));
  end;
  if (FModifyAction = lnDelete) then
  begin
    DeleteRecord(TZahlungsart(Ptr));
  end;
  inherited Notify(Ptr, Action);
end;

function TZahlungsartObjListe.Remove(Objekt: TZahlungsart): Integer;
begin
  Result := inherited Remove(Objekt);
end;

procedure TZahlungsartObjListe.setItem(Index: Integer;
  Objekt: TZahlungsart);
begin
  inherited Items[Index] := Objekt;
end;
Rolf Warnecke
App4Mission
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.008 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 13:39
1.) Ist das soweit schon mal richtig oder gibt es da noch Verbesserungen ? Wenn ja, was kann man im allgemeinen verbessern und auch in Bezug auf mehrere TObjectList<TKlassenname>.Create's ?
Was meinst du mit verbessern im Bezug auf das Create? Du kannst für jede TObjectList<TKlassenname> eine Redefinition machen, wie Uwe schon ansprach. Würd ich aber nicht empfehlen.
2.) Wie realisiere ich es, dass das OnChange-Event bei neuen Datensätzen ausgelöst wird ?
Listen haben das OnNotify Event, was dich über hinzufügen und entfernen von Datensätzen informiert. Du willst ja zusätzlich noch ein Notify haben, wenn sich innerhalb eines Listenelements was ändert. Da würde ich eine Ableitung von TObjectList<T> schreiben und das dort noch reinnehmen.
3.) In meiner alten Konstelation hatte ich noch eine extra Procedure für das Löschen eines Datensatzes, wie mache ich das hier in diesem Beispiel ?
Entweder mit Delete oder Remove, je nachdem ob du das konkrete Element hast oder den Index davon, beides geht.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von RWarnecke
RWarnecke

Registriert seit: 31. Dez 2004
Ort: Stuttgart
4.408 Beiträge
 
Delphi XE8 Enterprise
 
#5

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 13:59
Was meinst du mit verbessern im Bezug auf das Create?
Ob ich in meiner FormCreate aus Beitrag #1 soweit alles richtig gemacht habe oder ob es da noch etwas zu verbessern gibt.
Du kannst für jede TObjectList<TKlassenname> eine Redefinition machen, wie Uwe schon ansprach. Würd ich aber nicht empfehlen.
Warum empfiehlst Du das nicht. Ich brauche doch immer nur eine ObjectListe ? Oder habe ich da noch ein Verständnisproblem ?

Edit:
Ich habe mir jetzt mal eine Ableitung für TObjectList<TKlassenname> zusammengebaut, die anscheinend Recht gut funktioniert. Die komplette Datei findet Ihr im Anhang.
In der Delete-Procedure, lese ich über die RTTI den Klassennamen aus und dann werden entsprechend den ermittelten Namen die einzelnen DELETE SQL-Befehle ausgeführt. Oder ist die RTTI zu viel für das Auslesen des Klassennamens ?

Gibt es da noch Verbesserungsvorschläge ?
Angehängte Dateien
Dateityp: pas Unit3.pas (6,7 KB, 12x aufgerufen)
Rolf Warnecke
App4Mission

Geändert von RWarnecke (19. Jun 2011 um 14:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.995 Beiträge
 
Delphi 12 Athens
 
#6

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 19. Jun 2011, 16:07
Du kannst für jede TObjectList<TKlassenname> eine Redefinition machen, wie Uwe schon ansprach. Würd ich aber nicht empfehlen.
Da würde mich aber doch wirklich das Warum interessieren.

Eine Redefinition hat den Vorteil, daß sie sehr leicht geändert werden kann. Im einfachsten Fall ist es einfach nur ein Alias TZahlungsartList = TObjectList<TZahlungsart>; , den ich natürlich auch weglassen könnte. Wenn ich dann aber an 1001 Stellen eine Variable definiert und eine Instanz dieser Liste erzeugt habe und dann feststelle, daß ich doch eine Ableitung brauche, bin ich mit dem Alias in nahezu Null-Komma-Nichts fertig und muss die Deklarationen und Instanzierungen nicht alle ändern.

Ich würde im Gegenteil sogar (fast) immer empfehlen, eine generische Liste über einen Alias zu definieren. Der Code liest sich einfach auch flüssiger.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von RWarnecke
RWarnecke

Registriert seit: 31. Dez 2004
Ort: Stuttgart
4.408 Beiträge
 
Delphi XE8 Enterprise
 
#7

AW: Auf Änderungen in einer TObjectList<T> reagieren

  Alt 25. Jun 2011, 20:13
Hallo zusammen,

ich habe jetzt versucht das Beispiel aus Beitrag #5 auf mein Programm zu übertragen. Nur leider bekomme ich den Fehler : Internal Error URV1111. Dazu habe ich einige Beiträge gefunden, nur leider verstehe ich nicht ganz den Hintergrund, was da passiert. Anscheinend muss das irgendwas mit den Generics zu tun haben.

Hier die drei Beiträge die ich gefunden habe :
Link1
Link2
Link3

Ich benutze eine Ableitung von TObjectList<T> und in den Beiträgen wird von TArray<T> gesprochen. Kann mir bitte jemand weiterhelfen ?
Rolf Warnecke
App4Mission
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:55 Uhr.
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