Einzelnen Beitrag anzeigen

I.A

Registriert seit: 14. Jan 2007
83 Beiträge
 
#1

Nicht erkärliche EAccessVoilation

  Alt 25. Feb 2009, 12:48
Hallo,

Gestern habe ich sowohl meine eigenen Datensatzmaske als auch die eines DP Users, welche er mir freundlicherweise zur Verfügung gestellt hat, getesetet.

Dabei erhalte ich eine EAccessviolation, wobei das Programm an der im Kommentar beschribenen Stelle anhält. Die Eigenschaft TWinControl.Parent existiert aber definitiv laut Delphi Hilfe.

Wenn ich deshalb debugge, um die Ursache für die Exception zu finden, erhalte ich diese an jener Stelle, wo die Eigenschaft DataSoruce zugewiesen wird. In der Methode SetDataSource, wie im Listing unten zu sehen.

Daraufhin habe ich meine eigenen Version der Datensatzmaske getestet und erhalte ebenfalls eine EAccessViolation an jener Stelle, wo

Delphi-Quellcode:
function TCR_DB_Editor.GetRealParent : TWinControl;
var MYDBCtrlGrid : TMYDBCtrlGrid;
     tmp :TWinControl;
     Flag : boolean;
begin
     Flag := false;
     tmp := self.Parent;
     result := tmp;
     //showmessage(result.Name);
     while ( tmp.Parent <> nil ) AND (Flag =false) do //Hier hält das Programm an und wirft die
     begin //Exception aus
         if Pos('dbctrl', lowercase(tmp.ClassName )) > 0 then
         begin
             MYDBCtrlGrid := TMYDBCtrlGrid(tmp);
             result := MYDBCtrlGrid.Panel;
             Flag := true;
         end;
         tmp := tmp.Parent;
     end;
end;

procedure TCR_DB_Editor.SeTDataSource(Value: TDataSource);
begin
   if value <> nil then
   begin
      FDataLink.DataSource := Value; //Hier hält der Debugger an und wirft die Exception aus
   end;
end;

// Hier mein eigener Entwurf:

procedure TDBInputMask.SetDataSource(ADataSource: TDataSource);
var
  idx: Integer;
  obj: TObject;
  edit: TDBInputLine;
  chbox: TDBCheckBox;
  cobox: TDBComboBox;
  clbox: TDBLookUpComboBox;
  rdgrp: TDBRadioGroup;
  imemo: TMemo;
  irich: TRichEdit;
  image: TImage;
begin
  if FEdits.Count > 0 then FEdits.Clear;
  if (ADataSource<>nil) and (FDataSource<>ADataSource) then
  begin
    //Hier erhalte ich die Exception, aber hier EAbstractError
    FDataSource := ADataSource;
    FDataSource.DataSet.GetFieldNames(FEdits);
    FCount := FDataSource.DataSet.FieldCount;
    for idx := 0 to FCount - 1 do
    begin
      SetLabels(idx, TDBText.Create(self));
      //SetInputs(idx, TDBEdit.Create(self));
      obj := FInputs[idx];
      if obj is TDBInputLine then
      begin
        TDBInputLine(FInputs[idx]).DataSource := FDataSource;
        TDBInputLine(FInputs[idx]).DataField := FEdits[idx];
      end;
      if obj is TDBCheckBox then
      begin
        TDBCheckBox(FInputs[idx]).DataSource := FDataSource;
        TDBCheckBox(FInputs[idx]).DataField := FEdits[idx];
      end;
    end;
  end;

procedure Tdbform.OpenDataBase;
begin
  if dlgOpen.Execute then
  begin
    FFilename := dlgOpen.Filename;
    ClientDataSet.LoadFromFile(FFilename);
    ClientDataSet.Active := true;
    //CreateMask;
    FInputMask := TDBInputMask.Create(self);
    FInputMask.Top := 312;
    FInputMask.Left := 8;
    FInputMask.Width := 425;
    FInputMask.Height := 145;
    FInputMask.DataSource := DataSource;
    //Hier erhalte ich EAbstractError;
    FInputMask.Parent := self;
  end;
end;
Da nund die Exception in beiden Versionen auftritt, muss ja ein generelles Problem vorliegen. Möglicherweise ist die Methode zur Zuweisung der Datenquelle falsch. Aber wie wird ed dann richtig gemacht?

Sowohl FDataLink.DataSource als auch FDataSource sind doch letztlich nix anderes als Zeiger auf die Datenquelle. Deren Adresse hole ich von außen. Aber warum dann die Exception?

Gibt es zur Lösung des Problems ein Standardverfahren, das diese Exception vermeidet?

Bin mit meinem Latein am Ende. Warum funktioniert die Zuweisung nicht. Ich verwende für die Entwicklung Turbo Delphi Exploerer, die kostenlose Version ohne Updates.

In meiner Version erhalte ich nicht EAccessviolation, sondern EAbstractError. Deshalb noch die Definition meiner Basisklasse für meine Eingabemaske:

Delphi-Quellcode:
  TCustomInputMask = class(TScrollBox)
  private
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
    FCount: Integer;
    FInputs: TObjectList;
    FLabels: TObjectList;
    FMasks: TStrings;
  public
    { Public-Deklarationen }
    procedure CreateLabel(ACaption: TCaption); virtual;
    procedure CreateEdit(AEditMask: String); virtual;
    procedure CreateCheckBox(ACaption: String); virtual;
    procedure CreateComboBox; virtual;
    procedure CreateMask; virtual;
    procedure CreateMemo; virtual;
    procedure CreateRadioGroup(ACaptions: TStrings); virtual;
    procedure CreateRichEdit; virtual;
  end;

//Hier noch die Definition meiner eigenen Datensatzmaske.
  TDBInputMask = class(TCustomInputMask)
  //diese Klasse für Datenbankmasken verwenden
  //Feldanzahl, damit Anzahl Edits wird durch die Datenbank bestimmt
  private
    FDataSource: TDataSource;
    FEdits: TStrings; //Feldnamen nach Anzeigereihenfolge
    function GetInputs(Index: Integer): TObject;
    function GetLabels(Index: Integer): TDBText;
    function GetMasks(Index: Integer): String;
    function GetDataSource: TDataSource;

    procedure SetCount(ACount: Integer);
    procedure SetInputs(Index: Integer; AInput: TObject);
    procedure SetLabels(Index: Integer; ALabel: TDBText);
    procedure SetMasks(Index: Integer; AMask: String);

    procedure SetDataSource(ADataSource: TDataSource);
  public
    constructor Create(AOwner: TComponent);
    procedure CreateLabel(ACaption: TCaption); override;
    procedure CreateLabelCaptions(ACaptions: TStrings);
    procedure CreateEdit(AEditMask: String); override;
    procedure CreateCheckBox(ACaption: String); override;
    procedure CreateComboBox; override;
    procedure CreateMask; override;
    procedure CreateMemo; override;
    procedure CreateRadioGroup(ACaptions: TStrings); override;
    procedure CreateRichEdit; override;
    destructor Destroy; override;

    property Count: Integer read FCount write SetCount;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property Inputs[Index: Integer]: TObject read GetInputs write SetInputs;
    property Masks[Index: Integer]: String read GetMasks write SetMasks; default;
  end;
Die virtuellen Methoden waren vorher als virtual; abstract; deklariert. Wegen der EAbstractError Exception habe ich diese Methoden virtual; definiert und im Implementationsteil stehen leere Methodenrümpfe. Dennoch werde ich die Exception nicht los.

Weil aber bei der Einen Version die Exception, wenn auch EAccessviolation, statt EAbstractError, wie bei der Anderen Version während der Zuweisung der Datenquelle ausgelöst wird, habe ich die Frage in diesen Thread gepackt. Denn ich vermute, das die Fehlerursache irgendwo im Softwaredesign liegt. Egal, welche Exception letzlich ausgelöst wird.

Braucht Ihr, um helfen zu können noch mehr Quelltext? Dann teilt mir das bitte hier mit und ich werde die Quellen liefern. Die Datensatzmaske ist nichts sonderlich geheimes.
  Mit Zitat antworten Zitat