0x26res
0x26res

Reputation: 13882

Avoid wxFrame destroy when closing

I'd like to create wxFrame that won't get Destroyed when closed, so I can show them back later and also keep updating them even when they are hidden.

I tried to use SetExtraStyle(wxWS_EX_BLOCK_EVENTS) hopping that it won't propagate the wxCloseEvent to who ever is destroying it, but it did not help.

I found with the following solution. I have to create a handler that will handle the close event and hide the frame. In this case the event is not propagated furhter. But it's a bit heavy weight becasue I need to keep tack of the handler and delete it myself.

does Anyone have a smarter solution ?

    class FrameCloseHider
        : public wxEvtHandler
      {
      public:
        explicit FrameCloseHider(wxTopLevelWindow*);
        void internalOnQuit(wxCloseEvent&);
        wxTopLevelWindow* getFrame();
      private:
        wxTopLevelWindow*   frame_;
      };

     wxTopLevelWindow* FrameCloseHider::getFrame()
      {
        return this->frame_;
      }

      void FrameCloseHider::internalOnQuit(wxCloseEvent& obj)
      {
         this->frame_->Hide();
       }  

      FrameCloseHider::FrameCloseHider(wxTopLevelWindow* frame)
        :frame_(frame)
      {
        this->frame_->Connect(
          frame_->GetId(),
          wxEVT_CLOSE_WINDOW,
          wxCloseEventHandler(FrameCloseHider::internalOnQuit),
          NULL,
          this);
      }

Upvotes: 0

Views: 1145

Answers (1)

Pete
Pete

Reputation: 4812

If you take a look at the wxEvtHandler source code, you'll see that if you provide user data to connect, then it will be deleted when the connection is destroyed.

So, in your example, since wxEvtHandler inherits from wxObject, you should be able do this:

this->frame_->Connect(
  frame_->GetId(),
  wxEVT_CLOSE_WINDOW,
  wxCloseEventHandler(FrameCloseHider::internalOnQuit),
  this, // ** Use the event handler as the user data.
  this);

Now, since you want to ensure that this is only ever created on the heap, make the constructor of FrameCloseHider private and add a static function to make the connection instead:

public:
    static void ConnectTo(wxTopLevelWindow* frame) {
        FrameCloseHider* obj = new FrameCloseHider(frame);
        frame->Connect(
          frame->GetId(),
          wxEVT_CLOSE_WINDOW,
          wxCloseEventHandler(FrameCloseHider::internalOnQuit),
          obj,
          obj);
    }
private:
      FrameCloseHider::FrameCloseHider(wxTopLevelWindow* frame)
        :frame_(frame)
      {
      }

[note: you should probably make this exception safe by using an auto_ptr and releasing it after the connect call] You'll need to test to make sure that using an event handler for the user data in the connection doesn't crash it. It looks like it should be OK from the wx code but it is one of the more complicated aspects of wx and more difficult to tell for sure without spending more time which I don't really have.

You can make this more generic with some templates etc. I have done this but using a slightly different pattern with a singleton event handler that is not passed as the user data but having a separate object that handles the event.

Upvotes: 1

Related Questions