Einzelnen Beitrag anzeigen

blackdrake

Registriert seit: 21. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#8

Re: Bei einer Komponente ein Panel zwischenschalten

  Alt 30. Mär 2009, 10:09
Hallo.

Ich habe den Code nochmal ganz genau analysiert, Diagramme gemacht (Stichwort Hirnknoten) und einiges verbessert. Nun klappt es ohne AV beim Create. Im Destroy habe ich aber aufgrund der Owner Probleme. Selbst wenn das Destroy funktioniert, kommt die AV am Programmende. Ich habe verschiedene Varianten durchprobiert und im Quellcode kurz kommentiert. Könnt ihr mir bitte weiterhelfen?

Delphi-Quellcode:
type
  TPaneledImage = class(TImage)
  private
    FPanel: TPanel;
    procedure SetVisible(Value: boolean);
    function GetParent: TWinControl;
    function GetOwner: TComponent; reintroduce;
    function GetVisible: boolean;
  protected
    procedure SetParent(AParent: TWinControl); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    property Parent: TWinControl read GetParent write SetParent;
    property Visible: boolean read GetVisible write SetVisible;
    property Owner: TComponent read GetOwner;
  end;

constructor TPaneledImage.Create(AOwner: TComponent);
begin
  // Host-Panel erstellen
  FPanel := TPanel.Create(AOwner);

  // Eigenschaften für das Panel
  FPanel.BevelOuter := bvNone;

  // Das eigentliche Image erstellen
  inherited Create(FPanel); {1}
  // inherited Create(AOwner); {2}
  // inherited Create(Self); {3}

  // Unveränderliche Eigenschaften für das Image im Panel festlegen
  inherited SetParent(FPanel);
  Align := alClient;
  Visible := true;
end;

destructor TPaneledImage.Destroy;
begin
  // Zuerst das Panel freigeben. Das Panel wird zuerst Nil gesetzt, dann freigegeben.
  // Das Panel wird widerum uns zuerst freigeben, weswegen dieses Destroy ein zweites
  // Mal aufgerufen wird und die korrekte Freigabe von TObject einleitet.

  if Assigned(FPanel) then
  begin
    FreeAndNil(FPanel) // Diese Zeile wird 1x zuerst aufgerufen
  end
  else
  begin
    // Diese Zeile wird 1x danach aufgerufen
    inherited;
    // Hier wird zusätzlich einmal TPaneledImage.SetParent aufgerufen
  end;

  // Aber NACH Destroy gibts eine AV!
end;

function TPaneledImage.GetOwner: TComponent;
begin
  result := FPanel.Owner;
end;

function TPaneledImage.GetParent: TWinControl;
begin
  result := FPanel.Parent;
end;

function TPaneledImage.GetVisible: boolean;
begin
  result := FPanel.Visible;
end;

procedure TPaneledImage.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  // Das Image im Panel soll bei (0, 0) bleiben. Nur das Panel bewegt sich.
  inherited SetBounds(0, 0, AWidth, AHeight);

  FPanel.Left := ALeft;
  FPanel.Top := ATop;
  FPanel.Width := AWidth;
  FPanel.Height := AHeight;
end;

procedure TPaneledImage.SetParent(AParent: TWinControl);
begin
  if not Assigned(FPanel) then exit; // Verhindern einer AV bei Destroy

  if FPanel.Parent <> AParent then
  begin
    FPanel.Parent := AParent;
  end;
end;

procedure TPaneledImage.SetVisible(Value: boolean);
begin
  if FPanel.Visible <> Value then
  begin
    FPanel.Visible := Value;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: TPaneledImage;
begin
  x := TPaneledImage.Create(Self);
  try
    x.Parent := Self;
    x.AutoSize := true;
    x.Picture.LoadFromFile('C:\WINDOWS\Präriewind.BMP');
  finally
    x.Free; // Verursacht eine AV, wenn Programm später beendet wird
  end;
end;
Create-Versuch {1}

Self gehört Self.Panel
Self.Panel gehört Self.Owner

Create-Versuch {2}

Self gehört Self.Owner
Self.Panel gehört Self.Owner

Create-Versuch {3}

Self gehört Self (hä? )
Self.Panel gehört Self.Owner

Weitere Idee 4

Self gehört Self.Owner
Self.Panel gehört Self

Weitere Idee 5

Self gehört Self.Panel
Self.Panel gehört Self


Gruß
blackdrake
Daniel Marschall
  Mit Zitat antworten Zitat