]>
Commit | Line | Data |
---|---|---|
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 | |
6 | to help make it clear when and how you delete windows, or respond to user requests | |
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, | |
12 | in a frame or a dialog, wxWidgets calls \helpref{wxWindow::Close}{wxwindowclose}. This | |
13 | in turn generates an EVT\_CLOSE event: see \helpref{wxCloseEvent}{wxcloseevent}. | |
14 | ||
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 | |
18 | (\helpref{wxCloseEvent::CanVeto}{wxcloseeventcanveto} returns false), the window should always be destroyed, otherwise there is the option to | |
19 | ignore the request, or maybe wait until the user has answered a question | |
20 | before deciding whether it is safe to close. The handler for EVT\_CLOSE should | |
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. | |
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 | |
27 | for some window classes, wxWidgets delays actual deletion of the window until all events have been processed, | |
28 | since otherwise there is the danger that events will be sent to a non-existent window. | |
29 | ||
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 | ||
34 | \wxheading{How can the application close a window itself?} | |
35 | ||
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. | |
38 | If using Close(), you can pass a true argument to this function to tell the event handler | |
39 | that we definitely want to delete the frame and it cannot be vetoed. | |
40 | ||
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 | |
44 | by this process (return false), whereas Destroy definitely destroys the window. | |
45 | ||
46 | \wxheading{What is the default behaviour?} | |
47 | ||
48 | The default close event handler for wxDialog simulates a Cancel command, | |
49 | generating a wxID\_CANCEL event. Since the handler for this cancel event might | |
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). | |
52 | In other words, by default, the dialog {\it is not destroyed} (it might have been created | |
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(). | |
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 | ||
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 | |
72 | or not delete the window. | |
73 | ||
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 | { | |
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(); | |
87 | dialog->Destroy(); | |
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: | |
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. | |
104 | break; | |
105 | } | |
106 | } | |
107 | } | |
108 | \end{verbatim} | |
109 | }% | |
110 | ||
111 | \wxheading{How do I exit the application gracefully?} | |
112 | ||
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 | |
116 | is a virtual function, not an event handler). | |
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 |