Autor Beitrag
Nam
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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

ausblenden 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

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:
  private
    { Private-Deklarationen }
    procedure EineProzedur(Sender: TObject);
  public
    { Public-Deklarationen }
  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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 30



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: 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. :mahn: Wenn es sie gäbe, würde man ja nicht davon abraten... :roll:

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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 44

Win 7 Pro
RAD Studio 2010 Pro
BeitragVerfasst: Fr 24.11.06 19:45 
Hallo !

was auch gehen sollte, ist sowas:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 44

Win 7 Pro
RAD Studio 2010 Pro
BeitragVerfasst: Fr 24.11.06 23:57 
den kann man doch auslassen ... :) darum heißt die proc ja auch DoDeleteButtons
nach dem Motto:
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: Sa 25.11.06 11:07 
user profile iconManina 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.

user profile iconNam 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: 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 :roll: .

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
Nam Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Sa 25.11.06 14:29 
user profile iconNarses 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.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 25.11.06 14:30 
So ginge es:
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:
const
  WM_DESTROY_BTN  = WM_USER + 1;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    procedure DestoryButton(var msg : TMessage); message WM_DESTROY_BTN;
  end;

var
  Form1: TForm1;


implementation

{$R *.dfm}

{ TForm1 }

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 :oops:

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: Sa 25.11.06 15:15 
Achtung: Ich <> Threadersteller.

ausblenden 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)