| Autor |
Beitrag |
Nam
      
Beiträge: 24
|
Verfasst: Mi 22.11.06 23:07
Ich hab ein Programm geschrieben in dem alles bis auf das Formular zur Laufzeit erstellt wird. Soweit funktioniert alles gut. Gelegentlich will ich alles umgestalten, dann lösche ich alle Komponenten und erstelle sie neu. Auch das funktioniert fast. Das Erstellen und Löschen ist kein Problem.
Problematisch wird es wenn ich alles gelöscht und neu erstellt habe und dann die OnClick Prozedur zurück zum Ausgangspunkt kommen soll. Da scheint dann nichts zu sein oder was flasches. Ich bekomme eine EAccessViolation Meldung.
Leider kann ich hier nichts zeigen, da der Quellcode sehr komplex ist. Ansich ist da auch kein Fehler drinn. In der Killprozedur steht nur das hier
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| var i: Integer; begin for i := ComponentCount-1 downto 0 do begin Components[i].Free; end; end; |
Danach weiß er nicht wo er zurück soll.
Und bitte nicht sagen, daß das schon seine Richtigkeit hat. Ich hab einen Button auf das Formular plaziert und diese Prozedur über den plazierten Button gelöscht. Der Button wird zwar mitgelöscht, aber es gibt keine Fehlermeldung.
Anfürsich sehe ich da keinen großen Unterschied. Beide Male werden die Komponenten gekillt. Ein mal gibt es eine Fehlermeldung, das zweite Mal keine.
Ich hab hier ein kleines Demoprogramm geschrieben in dem ich ein wenig experimentiert habe. Es ist nicht das eigentliche Programm und das es mir geht. Außerdem werden hier nur zwei Komponenten erstellt
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:
| private procedure EineProzedur(Sender: TObject); public end;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.EineProzedur(Sender: TObject); begin TButton(Sender).Free; end;
procedure TForm1.Button1Click(Sender: TObject); begin with TButton.Create(Self) do begin Parent := Self; Name := 'ButtonX'; Left := 10; Top := 10; OnClick := EineProzedur; end;
with TButton.Create(Self) do begin Parent := Self; Name := 'ButtonY'; Left := 10; Top := 50; OnClick := EineProzedur; end; end; |
Mit Button1 erstelle ich zwei Buttons, ButtonX und ButtonY. Beide Buttons sind einer OnClick Prozedur zugewiesen, die die jeweilige Komponente löscht. Klicke ich zuerst auf ButtonX, dann gibt es eine Fehlermeldung. Klicke ich auf ButtonY, dann wird nur der Button entfernt. Klicke ich dann auf ButtonX, gibt es auch keine Fehlermeldung und der Button wird freigegeben.
Also beide Programme sind sehr unterschiedlich, aber ich hoffe, daß beide den gleichen Grund für die Fehler haben. Wer kann mir helfen und eine Lösung anbieten?
|
|
VaNaTiC
      
Beiträge: 30
|
Verfasst: Do 23.11.06 00:12
Ich konnte den Fehler nachvollziehen und hab das in der Hilfe gefunden:
Warning: Never explicitly free a component within one of its own event handlers or the event handler of a component it owns or contains. For example, don’t free a button, or the form that owns the button, in its OnClick event handler.
Schau mal in den Code von DestroyComponents()
Beim debuggen ist mir auch aufgefallen, dass die Exception nicht beim TButton(Sender).Free kommt, sondern
beim Aufräumen der OnClick-Methode (end;)
|
|
Nam 
      
Beiträge: 24
|
Verfasst: Do 23.11.06 09:33
Und nun? Wie kriege ich das Ganze trotzdem sauber gelöst ohne zu pfuschen. Denn dazu habe ich keine Lust. Irgendwie ist alles zu machen, aber wie macht man es sauber. Ich muß nun mal peer OnClick alles freigeben. Wer hat eine Lösung?
|
|
Nam 
      
Beiträge: 24
|
Verfasst: Fr 24.11.06 15:39
Hallo Leute, das kann doch nicht sein. Kann mir wirklich keiner helfen? Es kann doch nicht sein, daß keiner eine Idee hat. Ich komme hier leider nicht weiter. Hier hört mein Wissen auf. Ich könnte mir etwas zusammenbasteln, aber ich will nicht basteln.
Also wie kann man ich den Rückweg on OnClick abfangen? Eventuell Stack leeren? Ist das sauber programmiert? Wenn ja, wie macht man sowas? Oder weiß einer eine andere Idee?
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Fr 24.11.06 18:35
Moin!
Wenn die Delphi-Entwickler sagen, dass man Komponenten nicht in ihren Ereignissen freigeben soll, dann gibt es keine "saubere" Lösung.  Wenn es sie gäbe, würde man ja nicht davon abraten...
Was du in deinen Programmen machst, ist deine Sache; aber was du vor hast, geht nicht "sauber".
//EDIT: Hmmm... du könntest alternativ eine eigene Fensternachricht definieren, in deren Handler du die Komponenten freigibst. Im OnClick sendest du dir dann diese Nachricht.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Manina
      
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Fr 24.11.06 19:45
Hallo !
was auch gehen sollte, ist sowas:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| private MustDelete : Boolean; end;
FormCreate: begin MustDelete := FALSE; end;
ButtonClick: begin MustDelete := TRUE; end;
OnTimer: begin if MustDelete then begin MustDelete := FALSE; DoDeleteButtons; end; end; |
_________________ Gates, oder Gates nicht ?
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Fr 24.11.06 22:23
Der Timer ist doch auch eine Komponente, die dadurch gekillt wird -> was ja nicht geht.
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Manina
      
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Fr 24.11.06 23:57
den kann man doch auslassen ...  darum heißt die proc ja auch DoDelete Buttons
nach dem Motto:
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure DoDeleteButtons; var i : Integer; begin for i := ComponentCount - 1 downto 0 do if (Components[i] is TButton) then.... end; |
_________________ Gates, oder Gates nicht ?
|
|
Nam 
      
Beiträge: 24
|
Verfasst: Sa 25.11.06 00:20
Genauso habe ich es gemacht. Mit DownTo alles gelöscht.
Ich bin verzweifelt. Ich akzeptiere die Aussage der Entwickler, aber es gibt nichts was es nicht gibt. Somit müßte es auch hier eine Möglichkeit geben. Die Timermethode ist es leider nicht. Das ist zu sehr gebastelt und das will ich nicht. Kann man nicht den Stack beeinflussen. Was wäre wenn man ihn leeren würde. Das wäre durchaus sauber, denn wenn man die Komponente entfernt hat, dann darf man auch den Aufruf entfernen. Das ist die letzte Idee die ich noch habe. Wer weiß wie das geht?
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Sa 25.11.06 11:07
Manina hat folgendes geschrieben: | den kann man doch auslassen ... darum heißt die proc ja auch DoDeleteButtons
nach dem Motto: |
Die Prozedur rufst du aber im Timer auf oder im OnClick des Buttons oder... -> geht nicht.
Nam hat folgendes geschrieben: | | Somit müßte es auch hier eine Möglichkeit geben. Die Timermethode ist es leider nicht. Das ist zu sehr gebastelt und das will ich nicht. |
Wie wäre es, wenn du vor dem löschen eine temporäre Komponente erstellst (z.B. einen Timer), die alle anderen Komponenten löscht. Dann lässt du die neuen Komponenten erstellen und löscht danach den Timer.
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Nam 
      
Beiträge: 24
|
Verfasst: Sa 25.11.06 13:19
Jetzt nicht falsch verstehen, die Timer Methode ist nett, aber wie ich schon gesagt habe es ist zu sehr gebastelt. Erstens werde ich den Code nach der Fertigstellung veröffentlichen. Da will ich mir nicht nachsagen lassen, daß ich das Programm zusammengeklebt habe. Außerdem ist mir die Methode zu link. Was ist wenn die Timer Prozedur zu spät ausgeführt wird und ich schon an anderer Stelle die Komponenten neu erstelle. Dann kriege ich auch eine Fehlermeldung, weil sie die gleichen Namen benutzen. Nein, ich muß 100% sicher sein und das bin ich mit einer Timer Komponente nicht.
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Sa 25.11.06 13:50
Moin!
Sag mal, liest du auch die Vorschläge, die du bekommst, oder willst du nur meckern...
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Sa 25.11.06 14:09
Du kannst auch nen temporären Button oder sonstwas nehmen und du kannst dir sicher sein, dass das nicht zuspät ausgeführt wird  .
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Nam 
      
Beiträge: 24
|
Verfasst: Sa 25.11.06 14:22
Entschuldige, aber was verstehst du unter "Vorschläge"?
Ja, ich hab dein Hinweis gelesen und hab auch gesagt, daß es schade ist. Trotzdem ist da das Programm und das Problem immer noch da. Das heißt, daß es gelöst werden muß. Dafür, daß die Entwickler eine Empfehlung geben kann ich mir nichts kaufen. Das Programm kann nur so und nicht anders programmiert werden. Zum Zeitpunkt X will ich alle meine Komponenten auf dem Formular löschen und neue erstellen. Das Problem bleibt also. Ich hoff(t)e auf Vorschläge.
Dann die Idee mit dem Timer. Also gut, wenn ich mir ein privates Programm schreibe, dann kann ich mir alles basteln wie ich es will. Wenn interessiert es. Ab einen Punkt muß man allerdings sagen, daß das nicht die korrekte Art ist. Wenn ein Stück Tapete locker ist, dann kann man durchaus sein Kaugummi drunterkleben und die Tapete wieder drann machen. Ist eine Lösung, aber trotzdem nicht die professionelle Art.
Ich suche nach eine professionellen Lösung für das Problem. Ich hoffe damit deine Frage beantwortet zu haben. Ich suche nicht irgendeine Lösung, sondern eine die akzeptabel ist.
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Sa 25.11.06 14:29
Narses hat folgendes geschrieben: | | du könntest alternativ eine eigene Fensternachricht definieren, in deren Handler du die Komponenten freigibst. Im OnClick sendest du dir dann diese Nachricht. |
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Sa 25.11.06 14:30
So ginge es:
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:
| const WM_DESTROY_BTN = WM_USER + 1;
type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private public procedure DestoryButton(var msg : TMessage); message WM_DESTROY_BTN; end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin SendMessage(self.Handle, WM_DESTROY_BTN, Integer(Button1), 0); end;
procedure TForm1.DestoryButton(var msg: TMessage); begin if msg.Msg = WM_DESTROY_BTN then TButton(msg.WParam).Free; end; |
//Edit: Mist, zu langsam und auch noch das erste Mal überlesen 
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 25.11.06 14:31
Also, ich verstehe das grad nicht. Welche Delphi-Version benutzt du denn???
Wäre ja zu einfach, das im Profil anzugeben...
Naja, auf jeden Fall hab ich mal mit ein paar Versionen getestet. Die Methoden mit Components[i] und (die ich zusätzlich getestet habe) FindComponent('ButtonX') funktionieren unter Delphi 3, 7, 2005 und 2006...
Nur TButton(Sender) funktioniert unter Delphi 3 nicht, ab Delphi 7 jedoch funktioniert auch das.
Angehängt habe ich mal mein Testprogram inklusive Exe einmal mit Delphi 3 und einmal mit Delphi 2006 kompiliert...
Einloggen, um Attachments anzusehen!
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Sa 25.11.06 15:10
@jaenicke: Das geht auch, aber versuch mal mehre Komponenten mit der Schleife freizugeben, dann bekommst du einen "Abstrakten Fehler".
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 25.11.06 15:11
Da du so auf der Stackmanipulation bestehst:
Kannst du Assembler? Wenn nicht vergiss es! Und selbst wenn du es kannst: So einfach ist es auch dann nicht (jedenfalls nicht ohne den Programmablauf zu stören, denn es hat ja seinen Sinn, dass da noch Code kommt nachdem dein OnClick aufgerufen wurde!!!)
Die zweite Sache: Hast du dir eigentlch meine Beispiele mal angesehen? Es funktioniert doch, zumindest ab Delphi 3!
// EDIT: @GTA-Place: Hmm, ich weiss nicht genau, was du meinst. Free wird doch wohl überall implementiert sein, oder wo ist es das nicht?
// EDIT END
Der Fehler dürfte woanders in deinem Code liegen, wenn das mit Components[i] nicht geht. Da hast du vermutlich noch eine andere Komponente, die das übelnimmt, dass du sie löschst, weshalb auch immer. Du solltest wie oben bereits gepostet zusehen, dass du nur Buttons löschst.
Und dann noch was zur Neuerstellung deines gesperrten Topics:
Wenn du mit der Sperrung nicht einverstanden bist, dann kläre das mit dem Team (der Link unter dem Beitrag steht ja nicht ohne Grund da, der ist dafür gedacht). Einfach den Beitrag erneut zu erstellen ist eine Frechheit (und dass das gar nix bringt hast du ja gemerkt).
Abgesehen davon: Die Sperrung des Beitrags finde ich auch vollkommen in Ordnung, da es um das selbe Problem ging. Und wenn du das mit dem Stack unbedingt weiterverfolgen wolltest, dann hättest du das eínfach mal nochmal sagen können, wir lesen durchaus solche Fragen, ich war nachdem du das angesprochen hast nur anhand deiner Aussage | Zitat: | | Das wäre durchaus sauber, denn wenn man die Komponente entfernt hat, dann darf man auch den Aufruf entfernen |
davon ausgegangen, dass du dafür nicht unbedingt die nötigen Kenntnisse (Assembler z.B.) hast, denn so stimmt das nicht ganz. Und deshalb habe ich dazu nix gesagt...
Zuletzt bearbeitet von jaenicke am Sa 25.11.06 15:17, insgesamt 1-mal bearbeitet
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Sa 25.11.06 15:15
Achtung: Ich <> Threadersteller.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.Button1Click(Sender: TObject); var X: Integer; begin for X := ComponentCount - 1 downto 0 do Components[X].Free; end; |
Das hier geht nicht in Delphi 7.
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
|