Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Ein Object in TObjectList<T> löschen mit Ereignis (https://www.delphipraxis.net/171341-ein-object-tobjectlist-t-loeschen-mit-ereignis.html)

RWarnecke 1. Nov 2012 14:33

Delphi-Version: XE2

Ein Object in TObjectList<T> löschen mit Ereignis
 
Hallo zusammen,

ich habe folgende Klassen erstellt :
Delphi-Quellcode:
type
  TModifyActionList = (lnNone, lnAdded, lnChange, lnDelete);

  TDegree = class
  private
    FOnChange     : TNotifyEvent;
    FOnDelete     : TNotifyEvent;
    FModifyAction : TModifyActionList;
    FID           : Integer;
    FDegree       : string;
    procedure SetID(const Value: Integer);
    procedure SetDegree(const Value: string);
  public
    property ID           : Integer          read FID           write SetID;
    property Degree       : string           read FDegree       write SetDegree;
    property ModifyAction : TModifyActionList read FModifyAction write FModifyAction;
    property OnChange     : TNotifyEvent     read FOnChange     write FOnChange;
    property OnDelete     : TNotifyEvent     read FOnDelete     write FOnDelete;
  end;

  TCustomObjectList<T: class> = class(TObjectList<T>)
  private
    FOnChange    : TNotifyEvent;
    FOnDelete    : TNotifyEvent;
    FModifyAction : TModifyActionList;
    FNewRecord   : Boolean;
    procedure DeleteRecord(Klasse: T);
  protected
    function getItem(Index: Integer): T; virtual;
    procedure setItem(Index: Integer; Objekt: T); virtual;
    procedure Notify(const Item: T; Action: TCollectionNotification); override;
  public
    function Add(Objekt: T): Integer; virtual;
    function NewRecord(Objekt: T): Integer; virtual;
    function Remove(Objekt: T): Integer; virtual;
    function IndexOf(Objekt: T): Integer; virtual;
    procedure Insert(Index: Integer; Objekt: T); virtual;
    property Items[index: Integer]: T        read getItem      write setItem; default;
    property ModifyAction : TModifyActionList read FModifyAction write FModifyAction;
    property OnChange    : TNotifyEvent     read FOnChange    write FOnChange;
    property OnDelete    : TNotifyEvent     read FOnDelete    write FOnDelete;
  end;

{...}

{ TDegree }

procedure TDegree.SetDegree(const Value: string);
begin
  FDegree := Value;
  if (Assigned(FOnChange)) and (FModifyAction = lnChange) then
    FOnChange(Self);
end;

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

{ TCustomObjectList<T> }

function TCustomObjectList<T>.Add(Objekt: T): Integer;
begin
  FNewRecord := False;
  Result := inherited Add(Objekt);
end;

procedure TCustomObjectList<T>.DeleteRecord(Klasse: T);
begin
  // To do something
end;

function TCustomObjectList<T>.getItem(Index: Integer): T;
begin
  Result := T(inherited Items[Index]);
end;

function TCustomObjectList<T>.IndexOf(Objekt: T): Integer;
begin
  Result := inherited IndexOf(Objekt);
end;

procedure TCustomObjectList<T>.Insert(Index: Integer; Objekt: T);
begin
  inherited Insert(Index, Objekt);
end;

function TCustomObjectList<T>.NewRecord(Objekt: T): Integer;
begin
  FNewRecord := True;
  Result := inherited Add(Objekt);
end;

procedure TCustomObjectList<T>.Notify(const Item: T;
  Action: TCollectionNotification);
begin
  if (Assigned(FOnChange)) and (FNewRecord) and (Action <> cnRemoved) then
  begin
    FNewRecord := False;
    FOnChange(Self);
  end;
  if Action = cnRemoved then
  begin
    FOnDelete(Item);
  end;
  inherited Notify(Item, Action);
end;

function TCustomObjectList<T>.Remove(Objekt: T): Integer;
begin
  Result := inherited Remove(Objekt);
end;

procedure TCustomObjectList<T>.setItem(Index: Integer; Objekt: T);
begin
  inherited Items[Index] := Objekt;
end;
Das funktioniert auch alles soweit ganz gut, bis auf den Teil mit FOnDelete. Warum bekomme ich jedesmal bei der Zeile
Delphi-Quellcode:
FOnDelete(Item);
eine AccessViolation ? Wie kann ich das beheben und was habe ich falsch gemacht ?

Sir Rufo 1. Nov 2012 14:38

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Prüf doch mal mit
Delphi-Quellcode:
if Assigned( FOnDelete ) then
ab, ob da was zugewiesen ist ;)

RWarnecke 1. Nov 2012 14:56

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Habe ich das aus der OH für Assigned richtig verstanden, wenn ich folgende Zeilen Code chreibe :
Delphi-Quellcode:
  Degree := TDegree.Create;
  Degree.OnChange := TableEntryChange;
  Degree.OnDelete := TableEntryDelete;
  Degree.ID := FieldByName('ID').AsInteger;
  Degree.Degree := FieldByName('Degree').AsString;
  DegreeList.Add(Degree);
Dann gibt mir
Delphi-Quellcode:
Assigned(FOnDelete)
innerhalb der Klasse zurück, ob die Zeile
Delphi-Quellcode:
Degree.OnDelete := TableEntryDelete;
ausgeführt wurde oder nicht ? Wenn ja, dann ist es leider nicht der Fall.
Delphi-Quellcode:
Assigned(FOnDelete)
gibt immer False zurück. Warum ?

Der obere Code-Iteil wird in einer Schleife mehrmals wiederholt.

DeddyH 1. Nov 2012 15:03

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Eigentlich sollte Assigned nach der Methodenzuweisung true zurückliefern. Bau doch mal temporär einen Setter ein, setz dort einen Haltepunkt und schau, ob der angesprungen wird. Ich sehe in dem Code keinen Grund, wieso das nicht so sein sollte.

RWarnecke 1. Nov 2012 15:23

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Bei den Klassen geht er in den Setter und weißt auch den richtigen Wert zu. Kann es vielleicht daran liegen, dass erst der Delete-Befehl ausgeführt wird und er dann ins Notify springt von TCustomObjectList<T: class> ?

DeddyH 1. Nov 2012 15:32

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Ich habe es gerade nicht im Kopf, aber möglicherweise ist das Item zwischen dem Delete und dem Notify bereits freigegeben, das würde die AV erklären.

RWarnecke 1. Nov 2012 16:12

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe es jetzt mal getestet. Wenn ich bei der Zeile
Delphi-Quellcode:
if Action = cnRemoved then
einen Breakpoint setze, steht der Count von der ObjectList um einen reduziert. Das heißt für mich, dass erst das Objekt gelöscht wird und dann Notify ausgeführt wird. Um das Ergebnis noch zu verifizieren, habe ich die Procedure Delete mit in meine abgeleitet Klasse übernommen. Es ist wirklich so, das erst die Delete Procedure ausgeführt wird und dann das Notify. Ich habe jetzt mal zusätzlich in der Delete-Procedure eine Abfrage auf Assigned(FOnDelete) gemacht. Auch hier wird ein False ausgegeben, wie kann das sein ?

Meine TCustomObjectList<T: class> sieht jetzt so aus :
Delphi-Quellcode:
  TCustomObjectList<T: class> = class(TObjectList<T>)
  private
    FOnChange    : TNotifyEvent;
    FOnDelete    : TNotifyEvent;
    FModifyAction : TModifyActionList;
    FNewRecord   : Boolean;
    procedure SetOnDelete(const Value: TNotifyEvent);
    procedure SetOnChange(const Value: TNotifyEvent);
  protected
    function getItem(Index: Integer): T; virtual;
    procedure setItem(Index: Integer; Objekt: T); virtual;
    procedure Notify(const Item: T; Action: TCollectionNotification); override;
  public
    function Add(Objekt: T): Integer; virtual;
    procedure Delete(Index: Integer); virtual;
    function NewRecord(Objekt: T): Integer; virtual;
    function Remove(Objekt: T): Integer; virtual;
    function IndexOf(Objekt: T): Integer; virtual;
    procedure Insert(Index: Integer; Objekt: T); virtual;
    property Items[index: Integer]: T        read getItem      write setItem; default;
    property ModifyAction : TModifyActionList read FModifyAction write FModifyAction;
    property OnChange    : TNotifyEvent     read FOnChange    write SetOnChange;
    property OnDelete    : TNotifyEvent     read FOnDelete    write SetOnDelete;
  end;

{...}

{ TCustomObjectList<T> }

function TCustomObjectList<T>.Add(Objekt: T): Integer;
begin
  FNewRecord := False;
  Result := inherited Add(Objekt);
end;

procedure TCustomObjectList<T>.Delete(Index: Integer);
begin
  if Assigned(FOnDelete) then
    FOnDelete(Self);
  inherited Delete(Index);
end;

function TCustomObjectList<T>.getItem(Index: Integer): T;
begin
  Result := T(inherited Items[Index]);
end;

function TCustomObjectList<T>.IndexOf(Objekt: T): Integer;
begin
  Result := inherited IndexOf(Objekt);
end;

procedure TCustomObjectList<T>.Insert(Index: Integer; Objekt: T);
begin
  inherited Insert(Index, Objekt);
end;

function TCustomObjectList<T>.NewRecord(Objekt: T): Integer;
begin
  FNewRecord := True;
  Result := inherited Add(Objekt);
end;

procedure TCustomObjectList<T>.Notify(const Item: T;
  Action: TCollectionNotification);
begin
  if (Assigned(FOnChange)) and (FNewRecord) and (Action <> cnRemoved) then
  begin
    FNewRecord := False;
    FOnChange(Self);
  end;
  inherited Notify(Item, Action);
end;

function TCustomObjectList<T>.Remove(Objekt: T): Integer;
begin
  Result := inherited Remove(Objekt);
end;

procedure TCustomObjectList<T>.setItem(Index: Integer; Objekt: T);
begin
  inherited Items[Index] := Objekt;
end;

procedure TCustomObjectList<T>.SetOnChange(const Value: TNotifyEvent);
begin
  FOnChange := Value;
end;

procedure TCustomObjectList<T>.SetOnDelete(const Value: TNotifyEvent);
begin
  FOnDelete := Value;
end;
Bei
Delphi-Quellcode:
if Assigned(FOnDelete) then
steht der Count von TCustomObjectList<TDegree> noch auf der vollen Anzahl Objekte. Entweder verstehe ich hier etwas nicht oder es läuft irgendwas schief.

Edit:
Im Anhang meine DegreeList, nach dem Befüllen mit Daten. So wie ich das sehe, ist doch alles korrekt oder ?

himitsu 1. Nov 2012 16:42

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Zitat:

eine AccessViolation
Und was für eine?

Was sagt denn der debugger, wenn du dir kurz vor dem aufruf den Wert dieser Variable anzeigen läßt?

RWarnecke 1. Nov 2012 16:55

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Zitat:

Zitat von himitsu (Beitrag 1189378)
Und was für eine?

---------------------------
Debugger Exception Notification
---------------------------
Project Project14.exe raised exception class $C0000005 with message 'access violation at 0x00000000: read of address 0x00000000'.
---------------------------
Break Continue Help
---------------------------
Zitat:

Zitat von himitsu (Beitrag 1189378)
Was sagt denn der debugger, wenn du dir kurz vor dem aufruf den Wert dieser Variable anzeigen läßt?

Welchen Wert meinst Du ?

himitsu 1. Nov 2012 17:17

AW: Ein Object in TObjectList<T> löschen mit Ereignis
 
Delphi-Quellcode:
  if (Assigned(FOnChange)) and (FNewRecord) and (Action <> cnRemoved) then // hier hast'e geprüft
  begin
    FNewRecord := False;
    FOnChange(Self);
  end;
  if Action = cnRemoved then // hier nicht
  begin
    FOnDelete(Item); // hier haltepunkt hin und schauen was in FOnDelete steht, *1
  end;
1) aber vemutlich wirklich ein "nil".
Jedenfalls sieht die Exception danach aus, da dort zur Adresse 0 (nil) gesprungen wurde und weil dort kein ausführbarer Code steht, knallt es.
(aber natürlich kann es auch noch innerhalb einer verlinkten Methode knallen, aber da sollte der Debugger ebenfalls hilfreich sein)

Der schon genannte Trick mit dem Setter würde zmindestens zeigen, ob, wann und wo dieses Property verändert wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:17 Uhr.
Seite 1 von 3  1 23      

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