git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28106 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			131 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			TeX
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			TeX
		
	
	
	
	
	
\section{Window deletion overview}\label{windowdeletionoverview}
 | 
						|
 | 
						|
Classes: \helpref{wxCloseEvent}{wxcloseevent}, \helpref{wxWindow}{wxwindow}
 | 
						|
 | 
						|
Window deletion can be a confusing subject, so this overview is provided
 | 
						|
to help make it clear when and how you delete windows, or respond to user requests
 | 
						|
to close windows.
 | 
						|
 | 
						|
\wxheading{What is the sequence of events in a window deletion?}
 | 
						|
 | 
						|
When the user clicks on the system close button or system close command,
 | 
						|
in a frame or a dialog, wxWidgets calls \helpref{wxWindow::Close}{wxwindowclose}. This
 | 
						|
in turn generates an EVT\_CLOSE event: see \helpref{wxCloseEvent}{wxcloseevent}.
 | 
						|
 | 
						|
It is the duty of the application to define a suitable event handler, and
 | 
						|
decide whether or not to destroy the window.
 | 
						|
If the application is for some reason forcing the application to close
 | 
						|
(\helpref{wxCloseEvent::CanVeto}{wxcloseeventcanveto} returns false), the window should always be destroyed, otherwise there is the option to
 | 
						|
ignore the request, or maybe wait until the user has answered a question
 | 
						|
before deciding whether it is safe to close. The handler for EVT\_CLOSE should
 | 
						|
signal to the calling code if it does not destroy the window, by calling 
 | 
						|
\helpref{wxCloseEvent::Veto}{wxcloseeventveto}. Calling this provides useful information
 | 
						|
to the calling code.
 | 
						|
 | 
						|
The wxCloseEvent handler should only call \helpref{wxWindow::Destroy}{wxwindowdestroy} to
 | 
						|
delete the window, and not use the {\bf delete} operator. This is because
 | 
						|
for some window classes, wxWidgets delays actual deletion of the window until all events have been processed,
 | 
						|
since otherwise there is the danger that events will be sent to a non-existent window.
 | 
						|
 | 
						|
As reinforced in the next section, calling Close does not guarantee that the window
 | 
						|
will be destroyed. Call \helpref{wxWindow::Destroy}{wxwindowdestroy} if you want to be
 | 
						|
certain that the window is destroyed.
 | 
						|
 | 
						|
\wxheading{How can the application close a window itself?}
 | 
						|
 | 
						|
Your application can either use \helpref{wxWindow::Close}{wxwindowclose} event just as
 | 
						|
the framework does, or it can call \helpref{wxWindow::Destroy}{wxwindowdestroy} directly.
 | 
						|
If using Close(), you can pass a true argument to this function to tell the event handler
 | 
						|
that we definitely want to delete the frame and it cannot be vetoed.
 | 
						|
 | 
						|
The advantage of using Close instead of Destroy is that it will call any clean-up code
 | 
						|
defined by the EVT\_CLOSE handler; for example it may close a document contained in
 | 
						|
a window after first asking the user whether the work should be saved. Close can be vetoed
 | 
						|
by this process (return false), whereas Destroy definitely destroys the window.
 | 
						|
 | 
						|
\wxheading{What is the default behaviour?}
 | 
						|
 | 
						|
The default close event handler for wxDialog simulates a Cancel command,
 | 
						|
generating a wxID\_CANCEL event. Since the handler for this cancel event might
 | 
						|
itself call {\bf Close}, there is a check for infinite looping. The default handler
 | 
						|
for wxID\_CANCEL hides the dialog (if modeless) or calls EndModal(wxID\_CANCEL) (if modal).
 | 
						|
In other words, by default, the dialog {\it is not destroyed} (it might have been created
 | 
						|
on the stack, so the assumption of dynamic creation cannot be made).
 | 
						|
 | 
						|
The default close event handler for wxFrame destroys the frame using Destroy().
 | 
						|
 | 
						|
\wxheading{What should I do when the user calls up Exit from a menu?}
 | 
						|
 | 
						|
You can simply call \helpref{wxWindow::Close}{wxwindowclose} on the frame. This
 | 
						|
will invoke your own close event handler which may destroy the frame.
 | 
						|
 | 
						|
You can do checking to see if your application can be safely exited at this point,
 | 
						|
either from within your close event handler, or from within your exit menu command
 | 
						|
handler. For example, you may wish to check that all files have been saved.
 | 
						|
Give the user a chance to save and quit, to not save but quit anyway, or to cancel
 | 
						|
the exit command altogether.
 | 
						|
 | 
						|
\wxheading{What should I do to upgrade my 1.xx OnClose to 2.0?}
 | 
						|
 | 
						|
In wxWidgets 1.xx, the {\bf OnClose} function did not actually delete 'this', but signaled
 | 
						|
to the calling function (either {\bf Close}, or the wxWidgets framework) to delete
 | 
						|
or not delete the window.
 | 
						|
 | 
						|
To update your code, you should provide an event table entry in your frame or
 | 
						|
dialog, using the EVT\_CLOSE macro. The event handler function might look like this:
 | 
						|
 | 
						|
{\small%
 | 
						|
\begin{verbatim}
 | 
						|
  void MyFrame::OnCloseWindow(wxCloseEvent& event)
 | 
						|
  {
 | 
						|
    if (MyDataHasBeenModified())
 | 
						|
    {
 | 
						|
      wxMessageDialog* dialog = new wxMessageDialog(this,
 | 
						|
        "Save changed data?", "My app", wxYES_NO|wxCANCEL);
 | 
						|
 | 
						|
      int ans = dialog->ShowModal();
 | 
						|
      dialog->Destroy();
 | 
						|
 | 
						|
      switch (ans)
 | 
						|
      {
 | 
						|
        case wxID_YES:      // Save, then destroy, quitting app
 | 
						|
          SaveMyData();
 | 
						|
          this->Destroy();
 | 
						|
          break;
 | 
						|
        case wxID_NO:       // Don't save; just destroy, quitting app
 | 
						|
          this->Destroy();
 | 
						|
          break;
 | 
						|
        case wxID_CANCEL:   // Do nothing - so don't quit app.
 | 
						|
        default:
 | 
						|
          if (!event.CanVeto()) // Test if we can veto this deletion
 | 
						|
            this->Destroy();    // If not, destroy the window anyway.
 | 
						|
          else
 | 
						|
            event.Veto();     // Notify the calling code that we didn't delete the frame.
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
\end{verbatim}
 | 
						|
}%
 | 
						|
 | 
						|
\wxheading{How do I exit the application gracefully?}
 | 
						|
 | 
						|
A wxWidgets application automatically exits when the designated top window, or the
 | 
						|
last frame or dialog, is destroyed. Put any application-wide cleanup code in \helpref{wxApp::OnExit}{wxapponexit} (this
 | 
						|
is a virtual function, not an event handler).
 | 
						|
 | 
						|
\wxheading{Do child windows get deleted automatically?}
 | 
						|
 | 
						|
Yes, child windows are deleted from within the parent destructor. This includes any children
 | 
						|
that are themselves frames or dialogs, so you may wish to close these child frame or dialog windows
 | 
						|
explicitly from within the parent close handler.
 | 
						|
 | 
						|
\wxheading{What about other kinds of window?}
 | 
						|
 | 
						|
So far we've been talking about `managed' windows, i.e. frames and dialogs. Windows
 | 
						|
with parents, such as controls, don't have delayed destruction and don't usually have
 | 
						|
close event handlers, though you can implement them if you wish. For consistency,
 | 
						|
continue to use the \helpref{wxWindow::Destroy}{wxwindowdestroy} function instead
 | 
						|
of the {\bf delete} operator when deleting these kinds of windows explicitly.
 | 
						|
 |