How to free control inside its event handler?
Asked Answered
G

2

11

Does anybody know the trick, how to free control inside its event handler ? According delphi help it is not possible...

I want to free dynamicaly created TEdit, when Self.Text=''.

TAmountEdit = class (TEdit)
.
.
public
  procedure KeyUp(var Key: Word; Shift :TShiftState);
end;

procedure TAmountEdit.KeyUp(var Key: Word; Shift :TShiftState);
begin
inherited;
if Text='' then Free; // after calling free, an exception arises
end;

How should do to achieve the same effect?

Thanx

Garay answered 23/3, 2010 at 18:24 Comment(3)
Have you tried just starting a timer which frees the edit and then disables itself?Denizen
Hmm... good question. If this was a form, I'd call Release, but that's declared on TCustomForm, not on TControl or TComponent.Bounded
Good question. I needed something like that several times in the past.Leapt
B
16

The solution is to post a queued message to the control, which it responds to by destroying itself. Ny convention we use CM_RELEASE which is the private message used by TForm in its implementation of the Release method that performs an analogous task.

interface

type
  TAmountEdit = class (TEdit)
    ...
    procedure KeyUp(var Key: Word; Shift :TShiftState); override;
    procedure HandleRelease(var Msg: TMessage); message CM_RELEASE;
    ...
  end;

implementation

procedure TAmountEdit.KeyUp(var Key: Word; Shift :TShiftState);
begin
  inherited;
  if Text = '' then
    PostMessage(Handle, CM_RELEASE, 0, 0);
end;

procedure TAmountEdit.HandleRelease(var Msg: TMessage);
begin
  Free;
end;

The control is destroyed when the application next pumps its message queue.

Botha answered 23/3, 2010 at 18:34 Comment(2)
No need to declare a new message ID. Check out CM_RELEASE, which is designed specifically to do this for forms. But the basic idea is correct. +1Bounded
I would call this method a hack, because it is not 100% safe. Try use Release here: TForm2 = class(TForm) S:string; procedure WndProc(var Msg:TMessage);override; public constructor Create(AOwner:TComponent);override; //... constructor TForm2.Create(AOwner:TComponent); begin S:='abc'; inherited end; procedure TForm2.WndProc(var Msg:TMessage); begin inherited; S[2]:='x' {*} end;Coen
S
6

Before implementing this I would stop and ask "Is this really the best approach?"

Do you really want an edit control class that always destroys itself when key input results in the Text property becoming an empty string?

Is it not more likely to be the case that you have a specific form/dialog where this behaviour is required? In which case, there is no problem... you can free the edit control in the KeyUp event handled by the form without incurring an Access Violation.

Shack answered 24/3, 2010 at 1:3 Comment(8)
Yes, I know it. The problem is, that I have one (my own) component based on TCustomControl, which contains TAmountEdit Controls (not specified how many). Thats why I have to dynamicaly create them and later Free them according my rules... It is similar like tabs on the IE or FireFox, where I close the tab and it disappears... (Frees? I do not know... :-) )Garay
I see. But if your component creates the controls, then to my mind it should also be responsible for freeing them. The rules would seem to be set by the control containing the TAmountEdit controls, not by the TAmountEdit control itself. Your custom control would create a TAmountEdit then assign an event handler (that it implements) to the OnKeyUp() event of the TAmountEdit (note that technically your original question is not about handling an event but rather intercepting one!).Shack
:-) I do not concern about freeing TAmountEdit, while they are added to Components array of the containercontrol (it owns them). So they are freed automaticaly, when containercontrol is about to be destroyed. I intercept OnKeyUp() event of TAmountEdit anyway in order to navigate through them easily. To free TAmountEdit is its optional property and I wanted to implement it inside the control itself. Moreover I had some specific difficulties to free control from the parent just because of intercepting OnKeyUp event...Garay
It is far less problematic and less risky for a parent to free a child than it is for any object to free itself. But it's your funeral. :)Shack
I made Control for displaying messages. It is Panel with labels for username, date and message, and two buttons for Edit and Delete. I have two events: onEdit and onDelete. I want to remove component upon clicking the Delete button. I do that from a parent form in onDelete event handler, but still got Access Violation. I used solution proposed here but I don't like it a lot. Any suggestions.Sequestrate
You have to remember that even if the event is handled on the form, the event itself is called from code that is part of the instance of the control on your panel. You need to have the event "arrive" at the form independently of the control that is "sending" the event. One way to achieve this is to use PostMessage() to post a custom windows message to the form. This will only arrive and be processed by the form after the code in your control has finished executing.Shack
Don't confuse the question with the example. i want to initiate a database operation, and during OnExecuteComplete event handler i need to free the TADOConnection because it is time to clean it up. Or i want to issue an asynchronous http request, and during an event handler i need to free the object. i had hoped this question would have had an answer to the question "How to free control inside its event handler?", especially in the case when the control is not on a form.Interfluent
Ian, it doesn't matter what example you use, it is never a good idea to free ANY object inside the handler of an event originating from that object. The "how" is easy - you just Free it. Whether it is safe to do so is the important part. And there is simply no universally, guaranteed "safe" way to free an object directly in the middle of it's own event processing. Some objects, indeed some events on some objects, might allow you to get away with it, but any examples you find of this will be a lucky accident of implementation, not something that can be designed for.Shack

© 2022 - 2024 — McMap. All rights reserved.