Can a Button Delete Itself?

Posted on 2004-11-20
Last Modified: 2010-04-05
I have a button that has been created on the fly, which when clicked, executes a
procedure (say UpdateContent) which changes the content of a database then
destroys the button itself, then recalls the procedure (say LoadPage)
that created the button in the first place. It works OK except that it
brings up an error message whenever the code is run (AFTER the destroy
and recall functions of LoadPage have been executed) when the
line-by-line handling returns back to UpdateContent for the final end.
This is presumably because the button that called the procedure no
longer exists. Is there any simple way around this?
Question by:MartinC
    LVL 31

    Expert Comment

    If in the button click procedure you make a call to the OnClick event of a hidden button on the form, then I reckon that, within the hidden button procedure you will be able to delete the original button.  You can easily identify which button Sent the click by using Tag.
    LVL 1

    Expert Comment

    When you make the call to the OnClick event of the other button the program will start execution of that code which then deletes the first button. When the OnClick is completed however, it will return to the place where it was called from... the OnClick of the button you just deleted :)

    One way to do this is to use PostMessage to post a mouse click message...


    That way the OnCLick of the first button will be completed first after which the onClick of the 2nd button will be executed.

    Hope this helps,


    Author Comment

    morhouselondon: I'm afraid your solution just passes the buck one level higher. I tried a similar method at first, having the button's OnClick call a separate procedure entirely, but as wavget pointed out, eventually the code returns to the calling procedure just to do the "end" line, whereupon it falls over its own feet.

    wavget: that solution looks kinda ugly ... my own ugly solution was to have the button do UpdateContent then just set a boolean called bCleanup to true, without calling the LoadPage. Then I'd use the timer to sweep through every second looking for bCleanup = true, do the destroy and recall functions of LoadPage, and reset bCleanup to false. I have the timer on there already anyway as the application has a running clock in it, so there won't be much additional overhead resource-wise. But it is not a pretty solution ... can lead to problems later. Similarly, I'd rather not muck about with the actual comp's handling of the clicks if I can help it.

    Anyone got a more elegant solution?
    LVL 31

    Expert Comment

    Hmmm I dynamically delete panels on a form, but thinking about it I'm doing that from a popup menu, which is outside the scope of "pulling the rug from under oneself".

    I suppose my suggestion of creating a hidden button could have been simplified to saying: why not just Hide the original button and reuse it when necessary?  That depends on whether there is the possibility that multiple buttons will be created which need to be hidden/deleted.

    The idea of having a timed cleanup sweep sounds good.  
    LVL 26

    Accepted Solution


    The problem you are having is due to ignoring the warnings that delphi gives us in regards to the use of Free. To quote the help file:

    Warning:      Never explicitly free a component within one of its own event handlers or free a component from the event handler of a component it owns or contains. For example, don’t free a button in its OnClick event handler or free the form that owns the button from the button's OnClick event.

    Ignoring this will cause errors that are difficult to trace, or even worse, may not cause an immediate error, but will raise problems later on.

    Garbage collecting a component/object through timer polling is one way to get around this. Another would be to postmessage back to the form itself. An example of this is as follows:

    unit Unit1;


      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

    // Define a window message to use for internal handling
      WM_FREEOBJECT     =  WM_USER + 400;

      TForm1            =  class(TForm)
         Button1:       TButton;
         procedure      Button1Click(Sender: TObject);
         // Private declarations
         // Protected declarations
         procedure      WMFreeObject(var Message: TMessage); message WM_FREEOBJECT;
         // Public declarations
         procedure      DelayedFreeObject(Obj: TObject);

      Form1:            TForm1;

    {$R *.DFM}

    // Procedure to actually free objects
    procedure TForm1.WMFreeObject(var Message: TMessage);
    var  Obj:        TObject;
      // Check wParam
      if ((Message.wParam) <> 0) then
         // Access as TObject
         // Make sure Obj <> Self
         if (Obj <> Self) then Obj.Free;

    // Simple helper function to post message to the form, which will then handle the freeing of objects
    procedure TForm1.DelayedFreeObject(Obj: TObject);
      // Post free object message to form
      PostMessage(Handle, WM_FREEOBJECT, Integer(Obj), 0);

    procedure TForm1.Button1Click(Sender: TObject);
      // Delayed free of the object - exchange this with code that calls Button1.Free
      // to see the difference.
      // Call a property of the button just to test
      if Button1.Enabled then beep;



    After the event handling is done, the form will go back to its message processing, at which time the WM_FREEOBJECT message will be processed and handled. This provides a very simple, and relatively clean method of freeing an object from within its own event handler. I say relatively, due to the fact that the calling of


    can thow a monkey wrench into this, as it tells the application to handle any messages that are sitting in the message queue (one of which would be the WM_FREEOBJECT). I can tell you that the use of TTimer would also suffer from the same problem caused by Application.ProcessMessages, as it would allow the possibility for the ttimer to free an object while the  object is in its event handler.

    Anyways, regardless of the actual mechanism you use you cannot safely free a component/object from its own event handler. And if using a delayed mechanism to perform the free, then you need to make sure that you don't process the message queue while the object is in its event handler.

    Hope this helps,


    Author Comment

    Hmmm, sorry, I forgot I had left this question open, so I'll close it off now. I suspect my strategy was flawed from the outset and certainly the solutions presented above seem rather open to things going wrong later. So I have bitten the bullet and coded the database handling and the screen reconstruction to occur separately i.e. I never recall the LoadPage procedure that created the button in the first place, I just duplicate in the UpdateContent procedure some of the LoadPage handing code for screen generation that I had hoped to store in a single procedure.  

    Of the solutions above, rllibby's provided a comprehensive synopsis of the insoluble aspects of the problem which led me to make the decision to abandon the plan, so points to him. Thanks to others as well.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    How to run any project with ease

    Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
    - Combine task lists, docs, spreadsheets, and chat in one
    - View and edit from mobile/offline
    - Cut down on emails

    In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
    Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
    In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor ( If you're interested in additional methods for monitoring bandwidt…
    Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

    737 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    18 Experts available now in Live!

    Get 1:1 Help Now