From 1ad25bdd5c90223cd7c0b2ae53c0c94123c4dc17 Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Mon, 24 Feb 2020 00:57:09 +0200 Subject: [PATCH] Demonstrate how to interrupt closing an application Add a menu item to the dialogs sample for simulating having unsaved documents in the application. Then demonstrate how to do something when the user attempts to close the application, e.g. show a dialog, and possibly cancel closing. This code was originally written for debugging some issue related to closing an application, but besides that it serves as an example of a very common pattern a lot of real world applications need in some form. Mention the example in samples/dialogs in wxCloseEvent documentation --- interface/wx/event.h | 3 +++ samples/dialogs/dialogs.cpp | 53 ++++++++++++++++++++++++++++++++++++- samples/dialogs/dialogs.h | 6 ++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/interface/wx/event.h b/interface/wx/event.h index 82106239fd..b683b600de 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -4498,6 +4498,9 @@ public: } @endcode + See also @c samples/dialogs for a full example of interrupting closing an + application when there are e.g. unsaved files. + The EVT_END_SESSION event is slightly different as it is sent by the system when the user session is ending (e.g. because of log out or shutdown) and so all windows are being forcefully closed. At least under MSW, after the diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index a7ed02b5f5..637e999db4 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -288,6 +288,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(DIALOGS_STANDARD_BUTTON_SIZER_DIALOG, MyFrame::OnStandardButtonsSizerDialog) EVT_MENU(DIALOGS_TEST_DEFAULT_ACTION, MyFrame::OnTestDefaultActionDialog) EVT_MENU(DIALOGS_MODAL_HOOK, MyFrame::OnModalHook) + EVT_MENU(DIALOGS_SIMULATE_UNSAVED, MyFrame::OnSimulatedUnsaved) EVT_MENU(DIALOGS_REQUEST, MyFrame::OnRequestUserAttention) #if wxUSE_NOTIFICATION_MESSAGE @@ -303,6 +304,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) #endif // wxUSE_RICHTOOLTIP EVT_MENU(wxID_EXIT, MyFrame::OnExit) + EVT_CLOSE( MyFrame::OnClose) wxEND_EVENT_TABLE() #if USE_MODAL_PRESENTATION @@ -635,6 +637,7 @@ bool MyApp::OnInit() menuDlg->Append(DIALOGS_STANDARD_BUTTON_SIZER_DIALOG, "&Standard Buttons Sizer Dialog"); menuDlg->Append(DIALOGS_TEST_DEFAULT_ACTION, "&Test dialog default action"); menuDlg->AppendCheckItem(DIALOGS_MODAL_HOOK, "Enable modal dialog hook"); + menuDlg->AppendCheckItem(DIALOGS_SIMULATE_UNSAVED, "Simulate an unsaved document at exit"); menuDlg->AppendSeparator(); menuDlg->Append(wxID_EXIT, "E&xit\tAlt-X"); @@ -678,7 +681,7 @@ bool MyApp::OnInit() // My frame constructor MyFrame::MyFrame(const wxString& title) - : wxFrame(NULL, wxID_ANY, title) + : wxFrame(NULL, wxID_ANY, title), m_confirmExit(false) { SetIcon(wxICON(sample)); @@ -2984,11 +2987,59 @@ void MyFrame::OnModalHook(wxCommandEvent& event) s_hook.Unregister(); } +void MyFrame::OnSimulatedUnsaved(wxCommandEvent& event) +{ + m_confirmExit = event.IsChecked(); +} + void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event) ) { Close(true); } +void MyFrame::OnClose(wxCloseEvent& event) +{ + if ( m_confirmExit && event.CanVeto() ) + { + wxMessageDialog dialog(this, + "You have an unsaved file; save before closing?", + "OnClose", + wxCENTER | + wxYES_NO | wxCANCEL | + wxICON_QUESTION); + + dialog.SetYesNoLabels( + "&Save", + "&Discard changes" + ); + switch ( dialog.ShowModal() ) + { + case wxID_CANCEL: + event.Veto(); + wxLogStatus("You cancelled closing the application."); + // Return without calling event.Skip() to prevent closing the frame. + // The application should resume operation as if closing it had not + // been attempted. + return; + case wxID_YES: + wxMessageBox("You chose to save your file.", "OnClose", wxOK); + // In a real application, do something to save the + // file(s), possibly asking for a file name and location + // using wxFileDialog. + break; + default: + wxLogError("Unexpected wxMessageDialog return code!"); + wxFALLTHROUGH; + case wxID_NO: + // Don't save anything, and simply continue with closing the frame. + break; + } + } + + // Continue with closing the frame. + event.Skip(); +} + #if wxUSE_PROGRESSDLG static const int max_ = 100; diff --git a/samples/dialogs/dialogs.h b/samples/dialogs/dialogs.h index 4972a537e4..a026b0a157 100644 --- a/samples/dialogs/dialogs.h +++ b/samples/dialogs/dialogs.h @@ -517,8 +517,10 @@ public: void OnTestDefaultActionDialog(wxCommandEvent& event); void OnModalHook(wxCommandEvent& event); + void OnSimulatedUnsaved(wxCommandEvent& event); void OnExit(wxCommandEvent& event); + void OnClose(wxCloseEvent& event); private: #if wxUSE_COLOURDLG @@ -564,6 +566,7 @@ private: wxTipWindow *m_tipWindow; #endif // wxUSE_TIPWINDOW + bool m_confirmExit; wxDECLARE_EVENT_TABLE(); }; @@ -656,7 +659,8 @@ enum DIALOGS_PROPERTY_SHEET_BUTTONTOOLBOOK, DIALOGS_STANDARD_BUTTON_SIZER_DIALOG, DIALOGS_TEST_DEFAULT_ACTION, - DIALOGS_MODAL_HOOK + DIALOGS_MODAL_HOOK, + DIALOGS_SIMULATE_UNSAVED }; #endif