| Autor |
Beitrag |
matze
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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:
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
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;
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;
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];
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;
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; 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
      
Beiträge: 48
|
Verfasst: 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
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; type TMainForm = class(TForm) ... private procedure WMDeleteKompo(var Msg: TMessage); message WM_DeleteKompo; End;
implementation
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 Klabautermann: Code- durch Delphi-Tags ersetzt
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
      
Beiträge: 48
|
Verfasst: 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)
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TMainForm.WMDeleteKompo(var Msg: TMessage); begin Case Msg.WParam of 1: FreeAndNil(ProductPanel1); 2: FreeAndNil(ProductPanel2); 3: FreeAndNil(ProductPanel3); end; 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 matze: Code- durch Delphi-Tags ersetzt
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
      
Beiträge: 48
|
Verfasst: 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
Delphi-Quelltext 1: 2:
| Var PPanel: Array[1..30] of TProductPanel; |
In Form Create diese erstmal auf Nil setzen
Delphi-Quelltext 1:
| for i:=1 to 30 do PPanel[i]:=Nil; |
Und wenn du ein Panel brauchst dann
dieses per Funktion erzeugen
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| function CreatePPanel : Integer; var i: Integer; begin result:=-1; 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
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TMainForm.WMDeleteKompo(var Msg: TMessage); begin IF Assigned(PPanel[Msg.wParam]) then FreeAndNil(PPanel[Msg.wParam]); end; |
Moderiert von Klabautermann: Code- durch Delphi-Tags ersetzt
|
|
arcardia
      
Beiträge: 48
|
Verfasst: Mi 21.09.05 18:26
Mir fällt gerade noch was ganz simples ein
Und zwar...
einfach einen Typ deklarieren
ungefährt so...
Delphi-Quelltext 1: 2:
| Var WegWerfPanel : TProductPanel; |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TMainForm.MeineKompo.FreeButtonClick(Sender: TObject); Begin WegWerfPanel := TTProductPanel(Sender); PostMessage(Mainform.Handle,WM_DeleteKompo,0,0); end;
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 raziel: Code- durch Delphi-Tags ersetzt
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
      
Beiträge: 1905
W98, XP
D7 PE, Lazarus, WinAVR
|
Verfasst: 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 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: 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.
digi_c hat folgendes geschrieben: | | ... die Entsorgung mitsamt dem Panel durchzuführen ... |
Was meinst du damit?
Flo
|
|
digi_c
      
Beiträge: 1905
W98, XP
D7 PE, Lazarus, WinAVR
|
Verfasst: Mi 28.09.05 07:05
Na das in dem Destroy Ereignis des Panels auch die unsichtbaren Objekte freigegeben werden.
|
|