Autor Beitrag
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 21.09.05 14:06 
Hallo !
Ich bin gerade dabei eine eigene Komponente zu entwerfen. Diese ist ein Nachfahre von TPanel.
Auf diesem Panel liegen einige andere visuelle Komponenten. Unter anderem auch ein Button der das Parent Panel löschen soll.
wenn ich also in der OnClick Prozedur dieses Buttons ein self.free aufrufe wird das Panel zwar schon gelöscht, aber es erscheint eine Acess Violation.
Wenn ich das Panel von "ausserhalb", also z.b. aus einem button der auf dem form liegt lösche mittels meinekompo.free; wrid alles korrekt ausgeführt.

Wie kann ich also meine Komponente sich selbst löschen lassen ??

Danke,
Matze

PS:
Wen es interessiert. Hier ist der Quelltext der Kompo:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
interface

uses
  SysUtils, Classes, Controls, ExtCtrls, Graphics, StdCtrls, buttons, Spin;

type TOnInputChange = procedure (Sender: TComponent) of object;
type TOnDelRequest = procedure (Sender: TComponent) of object;

type
  TProductPanel = class(TPanel)
  private
    delButton:TSpeedButton;
    namelabel: TLabel;
    countlabel: TLabel;
    pricelabel: TLabel;
    gesamtlabel: TLabel;
    gesamtedit: Tedit;
    FOnInputChange: TOnInputChange;
    FOnDelRequest:TOnDelRequest;
    procedure PriceChange(sender:TObject);
    procedure OnDelete(sender:TObject);
    function calcPrice:double;
  protected

  public
    nameedit: Tedit;
    countedit: TSpinedit;
    priceedit: Tedit;
    property totalprice: double read calcPrice;
    constructor Create(Aowner: TComponent); override;
    destructor Destroy; override;
  published
    property OnInputChange: TonInputChange read FOnInputChange write FOnInputChange;
    property OnDelrequest: TOnDelRequest read FOnDelRequest write FOnDelRequest;
  end;


implementation

{ TProductPanel }

function TProductPanel.calcPrice: double;
begin
  result := countedit.Value * StrToFloatDef (stringreplace (priceedit.Text,'.',',',[rfReplaceAll]),0);
end;

constructor TProductPanel.Create(Aowner: TComponent);
begin
  inherited;
  width := 50;
  color := clInfoBk;

  { Create the Delete Button }
  delButton := TSpeedButton.Create(self);
  delbutton.Parent := self;
  delbutton.Font.Name := 'Marlett';
  delbutton.Caption := 'r';
  delbutton.Height := 16;
  delbutton.Width := 16;
  delbutton.Top := 3;
  delbutton.Left := self.Width - 3 - delbutton.Width;
  delbutton.Anchors := [akTop,akRight];
  delbutton.flat := true;
  delbutton.OnClick := OnDelete;

  { Create the Labels }
  namelabel := TLabel.Create(self);
  namelabel.Parent := self;
  namelabel.Caption := 'Artikelbezeichnung:';
  namelabel.Top := 3;
  namelabel.Left := 3;

  countlabel := TLabel.Create(self);
  countlabel.Parent := self;
  countlabel.Caption := 'Anzahl:';
  countlabel.Top := 3;
  countlabel.Left := self.Width - countlabel.Width - 250;
  countlabel.Anchors := [akTop,akRight];

  pricelabel := TLabel.Create(self);
  pricelabel.Parent := self;
  pricelabel.Caption := 'Preis/Stück:';
  pricelabel.Top := 3;
  pricelabel.Left := self.Width - pricelabel.Width - 150;
  pricelabel.Anchors := [akTop,akRight];

  gesamtlabel := TLabel.Create(self);
  gesamtlabel.Parent := self;
  gesamtlabel.Caption := 'Preis:';
  gesamtlabel.Top := 3;
  gesamtlabel.Left := self.Width - gesamtlabel.Width - 90;
  gesamtlabel.Anchors := [akTop,akRight];

  { Create the Edits }
  nameedit := TEdit.Create(self);
  nameedit.Parent := self;
  nameedit.Top := 20;
  nameedit.Left := 3;
  nameedit.Width := width - 300;
  nameedit.Anchors := [akTop,akRight,akLeft];

  countedit := TSpinEdit.Create(self);
  countedit.Parent := self;
  countedit.Top := 20;
  countedit.Left := self.Width - countlabel.Width - 250;
  countedit.Width := 60;
  countedit.Anchors := [akTop,akRight];
  countedit.MinValue := 0;
  countedit.MaxValue := 1000000;
  countedit.OnChange := PriceChange;

  priceedit := TEdit.Create(self);
  priceedit.Parent := self;
  priceedit.Top := 20;
  priceedit.Left := self.Width - pricelabel.Width - 150;
  priceedit.Width := 80;
  priceedit.Anchors := [akTop,akRight];
  priceedit.OnChange := PriceChange;

  gesamtedit := TEdit.Create(self);
  gesamtedit.Parent := self;
  gesamtedit.Top := 20;
  gesamtedit.Left := self.Width - gesamtlabel.Width - 90;
  gesamtedit.Width := 80;
  gesamtedit.Anchors := [akTop,akRight];
  gesamtedit.ReadOnly := true;
  gesamtedit.ParentCtl3D := false;
  gesamtedit.Ctl3D := false;
  gesamtedit.Font.Style := [fsbold];
  gesamtedit.Text := '0 €';
  gesamtedit.Color := self.color;

  { Create the Panel }
  align := altop;
  height := 50;
end;

destructor TProductPanel.Destroy;
begin
  delButton.free;
  namelabel.free;
  countlabel.free;
  pricelabel.free;
  gesamtlabel.free;
  gesamtedit.free;
  nameedit.free;
  countedit.free;
  priceedit.free;
  inherited Destroy;
end;

procedure TProductPanel.OnDelete(sender: TObject);
begin
  self.Free;
 // if Assigned (FOnDelRequest) then
    //FOnDelRequest(self);
end;

procedure TProductPanel.PriceChange(sender: TObject);
begin
  gesamtedit.Text := FloatToStrF(calcPrice,ffcurrency,7,2);
  if Assigned (FOnInputChange) then
    FOnInputChange(self);
end;

end.

_________________
In the beginning was the word.
And the word was content-type: text/plain.
arcardia
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48



BeitragVerfasst: Mi 21.09.05 14:23 
Das ganze geht nur per PostMessage
da du mit Free der Komponente ansonsten den eigenen Callback
unterm Ar... wegreisst


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
Const
   WM_DeleteKompo= WM_USER+101;     // Botschaft um zu löschen
type
  TMainForm = class(TForm)
  ...
  private
    (* Procedure fürs löschen*)
    procedure WMDeleteKompo(var Msg: TMessage); message WM_DeleteKompo;
  End;


implementation


// Diese Procedure löscht die Komponente
procedure TMainForm.WMDeleteKompo(var Msg: TMessage);
begin
  FreeAndNil(MeineKompo);
end;



procedure TMainForm.MeineKompo.FreeButtonClick(Sender: TObject);
Begin
  PostMessage(Mainform.Handle,WM_DeleteKompo,0,0);
end;


Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt
matze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 21.09.05 17:28 
ja das ist schonmal ne gute idee, allerdings in der form nicht so wirkich brauchbar, da ich auf meiner Form mehrer solcher komps habe und die ja dann beim Eintreffen der Window-Nachricht alle gelöscht werden würden.
Wie könnte ich denn das gezielt auf eine kompo machen ?

_________________
In the beginning was the word.
And the word was content-type: text/plain.
arcardia
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48



BeitragVerfasst: Mi 21.09.05 17:40 
Du kannst der Botschaft mit Hilfe von wParam und lParam einen Integer mitgeben
damit könntest du dann den Tag des Panels übergeben
(jedes Panel muss natürlich ein eindeutiges Tag haben)


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
// Diese Procedure löscht die Komponente  
procedure TMainForm.WMDeleteKompo(var Msg: TMessage);  
begin  
  Case Msg.WParam of
    1: FreeAndNil(ProductPanel1);
    2: FreeAndNil(ProductPanel2);
    3: FreeAndNil(ProductPanel3);
  end;
  // Oder noch besser das ganze mit FindComponent machen
end;  


procedure TMainForm.MeineKompo.FreeButtonClick(Sender: TObject); 
Var TagID: Integer;
begin
  TagID := TProductPanel(Sender).Tag;
  PostMessage(Mainform.Handle,WM_DeleteKompo,TagID,0); 
end;


Moderiert von user profile iconmatze: Code- durch Delphi-Tags ersetzt
matze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 21.09.05 17:52 
ja das könnte man machen. Das Problem ist nur:
Da ich die Komponenten von verschiedenen Stellen im Code erstelle - Wie kann ich da einen eindeutigen Wert der Tag Eigenschaft zuweisen ?

Irgendwie wird das ganze dann ein wenig kompliziert....

_________________
In the beginning was the word.
And the word was content-type: text/plain.
arcardia
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48



BeitragVerfasst: Mi 21.09.05 18:17 
Du könntest einen Integer als Merker nehmen und den
jeweils inkrementieren sofern du ein Panel erzeugst

oder wenn du die Panels eh dynamisch erzeugst
kannste die auch in Array packen

ausblenden Delphi-Quelltext
1:
2:
Var
 PPanel: Array[1..30] of TProductPanel;


In Form Create diese erstmal auf Nil setzen

ausblenden Delphi-Quelltext
1:
 for i:=1 to 30 do PPanel[i]:=Nil;					


Und wenn du ein Panel brauchst dann
dieses per Funktion erzeugen


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function CreatePPanel : Integer;
var i: Integer;
begin
  result:=-1;
  // Ein bislang noch freies Plätzchen finden
  For i:=1 to 30 do
   IF not Assigned(PPanel[i]) then Begin
      PPanel[i]:=TProductPanel.Create(Nil);
      PPanel[i].Tag := I;
      Result:= I;
      Exit;
   End;
End;




Wenn dann das Panel zerstört wird
währe der Platz wieder frei im Array

Wichtig ist dann das du FreeAndNil() anstatt
Free verwendest wenn das Panel zerstört wird

also so

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
// Diese Procedure löscht die Komponente    
procedure TMainForm.WMDeleteKompo(var Msg: TMessage);    
begin
  IF Assigned(PPanel[Msg.wParam]) then
     FreeAndNil(PPanel[Msg.wParam]);
end;


Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt
arcardia
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48



BeitragVerfasst: Mi 21.09.05 18:26 
Mir fällt gerade noch was ganz simples ein :)

Und zwar...

einfach einen Typ deklarieren
ungefährt so...


ausblenden Delphi-Quelltext
1:
2:
 Var
   WegWerfPanel : TProductPanel;



ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TMainForm.MeineKompo.FreeButtonClick(Sender: TObject);  
Begin  
  WegWerfPanel := TTProductPanel(Sender);  // Verweis auf das Panel
  PostMessage(Mainform.Handle,WM_DeleteKompo,0,0);  
end; 


// Diese Procedure löscht die Komponente  
procedure TMainForm.WMDeleteKompo(var Msg: TMessage);  
begin  
  IF Assigned(WegWerfPanel) then FreeAndNil(WegWerfPanel);  
end;




damit brauchste nix in Array packen und nix mit Tags merken
hoffe das geht soweit

Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt
matze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 21.09.05 21:08 
hey, deine zweite methode klingt ganz gut. das ist zwar vielleicht nicht so die methode wie man das machen sollte, aber es ist schonmal ganz gut !
ich werde mir das ganze mal durch den kopf gehen lassen.
Ich danke dir aber auf alle Fälle schon mal für die kreative und gute Hilfestellung !

Matze

_________________
In the beginning was the word.
And the word was content-type: text/plain.
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Do 22.09.05 09:34 
Wäre es nicht ausreichent Visible auf false zu setzen und die Entsorgung mitsamt dem Panel durchzuführen oder hat dein Wunsch eine tiefere Bewandnis?
matze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Do 22.09.05 10:22 
ja warscheinlich wird es auf sowas rauslaufen !
und die funktion der kompo in dem ganzen programm zu erläutern wird estwas zu lang.

_________________
In the beginning was the word.
And the word was content-type: text/plain.
flow31
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Fr 23.09.05 19:49 
Hallo!

Ich hab des gleiche Problem,
das mit den Botschaften erscheint mir aber ziemlich umständlich, wenn man mehrere solcher Komponenten hat.

Ich habs bis jetzt mit Visible := false gemacht, aber dann bleibt die Komponente ja trotzdem im Speicher.

user profile icondigi_c hat folgendes geschrieben:
... die Entsorgung mitsamt dem Panel durchzuführen ...

Was meinst du damit?

Flo
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Mi 28.09.05 07:05 
Na das in dem Destroy Ereignis des Panels auch die unsichtbaren Objekte freigegeben werden.