]>
Commit | Line | Data |
---|---|---|
a660d684 KB |
1 | \section{Window deletion overview}\label{windowdeletionoverview} |
2 | ||
3 | Classes: \helpref{wxCloseEvent}{wxcloseevent}, \helpref{wxWindow}{wxwindow} | |
4 | ||
5 | Window deletion can be a confusing subject, so this overview is provided | |
532372a3 | 6 | to help make it clear when and how you delete windows, or respond to user requests |
a660d684 KB |
7 | to close windows. |
8 | ||
9 | \wxheading{What is the sequence of events in a window deletion?} | |
10 | ||
11 | When the user clicks on the system close button or system close command, | |
fc2171bd | 12 | in a frame or a dialog, wxWidgets calls \helpref{wxWindow::Close}{wxwindowclose}. This |
f4fcc291 | 13 | in turn generates an EVT\_CLOSE event: see \helpref{wxCloseEvent}{wxcloseevent}. |
a660d684 | 14 | |
e3065973 JS |
15 | It is the duty of the application to define a suitable event handler, and |
16 | decide whether or not to destroy the window. | |
17 | If the application is for some reason forcing the application to close | |
cc81d32f | 18 | (\helpref{wxCloseEvent::CanVeto}{wxcloseeventcanveto} returns false), the window should always be destroyed, otherwise there is the option to |
a660d684 | 19 | ignore the request, or maybe wait until the user has answered a question |
f6bcfd97 | 20 | before deciding whether it is safe to close. The handler for EVT\_CLOSE should |
e3065973 JS |
21 | signal to the calling code if it does not destroy the window, by calling |
22 | \helpref{wxCloseEvent::Veto}{wxcloseeventveto}. Calling this provides useful information | |
23 | to the calling code. | |
a660d684 KB |
24 | |
25 | The wxCloseEvent handler should only call \helpref{wxWindow::Destroy}{wxwindowdestroy} to | |
26 | delete the window, and not use the {\bf delete} operator. This is because | |
fc2171bd | 27 | for some window classes, wxWidgets delays actual deletion of the window until all events have been processed, |
a660d684 KB |
28 | since otherwise there is the danger that events will be sent to a non-existent window. |
29 | ||
532372a3 JS |
30 | As reinforced in the next section, calling Close does not guarantee that the window |
31 | will be destroyed. Call \helpref{wxWindow::Destroy}{wxwindowdestroy} if you want to be | |
32 | certain that the window is destroyed. | |
33 | ||
a660d684 KB |
34 | \wxheading{How can the application close a window itself?} |
35 | ||
e3065973 JS |
36 | Your application can either use \helpref{wxWindow::Close}{wxwindowclose} event just as |
37 | the framework does, or it can call \helpref{wxWindow::Destroy}{wxwindowdestroy} directly. | |
cc81d32f | 38 | If using Close(), you can pass a true argument to this function to tell the event handler |
e3065973 | 39 | that we definitely want to delete the frame and it cannot be vetoed. |
a660d684 | 40 | |
e3065973 JS |
41 | The advantage of using Close instead of Destroy is that it will call any clean-up code |
42 | defined by the EVT\_CLOSE handler; for example it may close a document contained in | |
43 | a window after first asking the user whether the work should be saved. Close can be vetoed | |
cc81d32f | 44 | by this process (return false), whereas Destroy definitely destroys the window. |
a660d684 KB |
45 | |
46 | \wxheading{What is the default behaviour?} | |
47 | ||
e3065973 | 48 | The default close event handler for wxDialog simulates a Cancel command, |
a660d684 | 49 | generating a wxID\_CANCEL event. Since the handler for this cancel event might |
e3065973 JS |
50 | itself call {\bf Close}, there is a check for infinite looping. The default handler |
51 | for wxID\_CANCEL hides the dialog (if modeless) or calls EndModal(wxID\_CANCEL) (if modal). | |
532372a3 | 52 | In other words, by default, the dialog {\it is not destroyed} (it might have been created |
e3065973 JS |
53 | on the stack, so the assumption of dynamic creation cannot be made). |
54 | ||
55 | The default close event handler for wxFrame destroys the frame using Destroy(). | |
a660d684 KB |
56 | |
57 | \wxheading{What should I do when the user calls up Exit from a menu?} | |
58 | ||
59 | You can simply call \helpref{wxWindow::Close}{wxwindowclose} on the frame. This | |
60 | will invoke your own close event handler which may destroy the frame. | |
61 | ||
62 | You can do checking to see if your application can be safely exited at this point, | |
63 | either from within your close event handler, or from within your exit menu command | |
64 | handler. For example, you may wish to check that all files have been saved. | |
65 | Give the user a chance to save and quit, to not save but quit anyway, or to cancel | |
66 | the exit command altogether. | |
67 | ||
68 | \wxheading{What should I do to upgrade my 1.xx OnClose to 2.0?} | |
69 | ||
fc2171bd JS |
70 | In wxWidgets 1.xx, the {\bf OnClose} function did not actually delete 'this', but signaled |
71 | to the calling function (either {\bf Close}, or the wxWidgets framework) to delete | |
a660d684 KB |
72 | or not delete the window. |
73 | ||
a660d684 KB |
74 | To update your code, you should provide an event table entry in your frame or |
75 | dialog, using the EVT\_CLOSE macro. The event handler function might look like this: | |
76 | ||
77 | {\small% | |
78 | \begin{verbatim} | |
79 | void MyFrame::OnCloseWindow(wxCloseEvent& event) | |
80 | { | |
a660d684 KB |
81 | if (MyDataHasBeenModified()) |
82 | { | |
83 | wxMessageDialog* dialog = new wxMessageDialog(this, | |
84 | "Save changed data?", "My app", wxYES_NO|wxCANCEL); | |
85 | ||
86 | int ans = dialog->ShowModal(); | |
e3065973 | 87 | dialog->Destroy(); |
a660d684 KB |
88 | |
89 | switch (ans) | |
90 | { | |
91 | case wxID_YES: // Save, then destroy, quitting app | |
92 | SaveMyData(); | |
93 | this->Destroy(); | |
94 | break; | |
95 | case wxID_NO: // Don't save; just destroy, quitting app | |
96 | this->Destroy(); | |
97 | break; | |
98 | case wxID_CANCEL: // Do nothing - so don't quit app. | |
99 | default: | |
e3065973 JS |
100 | if (!event.CanVeto()) // Test if we can veto this deletion |
101 | this->Destroy(); // If not, destroy the window anyway. | |
102 | else | |
103 | event.Veto(); // Notify the calling code that we didn't delete the frame. | |
a660d684 KB |
104 | break; |
105 | } | |
106 | } | |
107 | } | |
108 | \end{verbatim} | |
109 | }% | |
110 | ||
111 | \wxheading{How do I exit the application gracefully?} | |
112 | ||
caddf9b4 VZ |
113 | A wxWidgets application automatically exits when the last top level window |
114 | (\helpref{wxFrame}{wxframe} or \helpref{wxDialog}{wxdialog}), is destroyed. Put | |
115 | any application-wide cleanup code in \helpref{wxApp::OnExit}{wxapponexit} (this | |
e3065973 | 116 | is a virtual function, not an event handler). |
a660d684 KB |
117 | |
118 | \wxheading{Do child windows get deleted automatically?} | |
119 | ||
120 | Yes, child windows are deleted from within the parent destructor. This includes any children | |
121 | that are themselves frames or dialogs, so you may wish to close these child frame or dialog windows | |
122 | explicitly from within the parent close handler. | |
123 | ||
124 | \wxheading{What about other kinds of window?} | |
125 | ||
126 | So far we've been talking about `managed' windows, i.e. frames and dialogs. Windows | |
127 | with parents, such as controls, don't have delayed destruction and don't usually have | |
128 | close event handlers, though you can implement them if you wish. For consistency, | |
129 | continue to use the \helpref{wxWindow::Destroy}{wxwindowdestroy} function instead | |
130 | of the {\bf delete} operator when deleting these kinds of windows explicitly. | |
131 |