Directory
- Window Close procedure
- Invoke process
- Close Document
- Delete a view
- Delete a Document object
- Close Frame
- App cleanup
- Multiple closing of the file window
- Formal deletion of Windows
- Summary of window closing process
- How to manually delete a view
Window Close procedure Call process
When the user clicks the Close button of the window, the WIN32 system sends a message to the current frame object WM_CLOSE
, which is then entered into the frame's wxFrame::MSWWindowProc
function for processing:
WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam){ switch ( message ) { case WM_CLOSE: // if we can‘t close, tell the system that we processed the // message - otherwise it would close us processed = !Close(); break;...
Close
The method is wxWindowBase
provided by the class, and the calling procedure is as follows:
- Creates a
wxEVT_CLOSE_WINDOW
message that passes the current Windowid
- Invokes the current object's message handler function for processing.
bool wxWindowBase::Close(bool force){ wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); event.SetEventObject(this); event.SetCanVeto(!force); // return false if window wasn‘t closed because the application vetoed the // close event return HandleWindowEvent(event) && !event.GetVeto();}
To continue tracking wxEVT_CLOSE_WINDOW
the processing of messages, we have the inheritance of the frame window that introduces the single document as follows, we can find the message handler based on this inheritance relationship:
wxDocParentFrame -> wxDocParentFrameBase (wxDocParentFrameAny < wxFrame > ) -- wxFrame & wxDocParentFrameAnyBase
We can find the wxDocParentFrameAny
Create
handler function that registers the message in the method in the template class wxEVT_CLOSE_WINDOW
wxDocParentFrameAny<>::OnCloseWindow
:
// wxDocParentFrameAny < >bool Create(wxDocManager *manager, ...){ m_docManager = manager; if ( !BaseFrame::Create(frame, id, title, pos, size, style, name) ) return false; this->Connect(wxID_EXIT, wxEVT_MENU, wxCommandEventHandler(wxDocParentFrameAny::OnExit)); this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxDocParentFrameAny::OnCloseWindow)); return true;}
wxDocParentFrameAny<>::OnCloseWindow
Will invoke m_docManager
the clear method to implement the shutdown, as long as the MVC class, there must be a document management class.
// wxDocParentFrameAny < >void OnCloseWindow(wxCloseEvent& event){ if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) { // The user decided not to close finally, abort. event.Veto(); } else { // Just skip the event, base class handler will destroy the window. event.Skip(); }}
Then we look at how the following document management classes are wxDocManager::Clear
implemented:
- Call
CloseDocuments
Close all documents, this step is critical, close the key path of the document;
- Because
wxDocManager
you manage multiple document templates, all document template objects need to be deleted at this time.
bool wxDocManager::Clear(bool force){ if (!CloseDocuments(force)) return false; m_currentView = NULL; wxList::compatibility_iterator node = m_templates.GetFirst(); while (node) { wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); wxList::compatibility_iterator next = node->GetNext(); delete templ; node = next; } return true;}
Follow the critical path wxDocManager::CloseDocuments
, where the steps are to find all the documents managed by this document manager and then invoke the CloseDocument
method to close the document:
bool wxDocManager::CloseDocuments(bool force){ wxList::compatibility_iterator node = m_docs.GetFirst(); while (node) { wxDocument *doc = (wxDocument *)node->GetData(); wxList::compatibility_iterator next = node->GetNext(); if (!CloseDocument(doc, force)) return false; node = next; } return true;}
To perform a close document operation, several steps:
- Call the method of the Doc class to
Close
execute the shutdown;
- Call the Doc class
DeleteAllViews
method to close the view associated with this document;
- Delete Document Object
bool wxDocManager::CloseDocument(wxDocument* doc, bool force){ if ( !doc->Close() && !force ) return false; doc->DeleteAllViews(); if (m_docs.Member(doc)) delete doc; return true;}
Close Document
wxDocManager
The method that invokes the document class wxDocument::Close
performs a close, and the default implementation of this method is to close all child document objects associated with this document class, and then invoke methods that the user can implement OnCloseDocument
.
OnCloseDocument
The default implementation is simply to clean up.
bool wxDocument::Close(){ if ( !OnSaveModified() ) return false; DocsList::const_iterator it = m_childDocuments.begin(); for ( DocsList::const_iterator end = m_childDocuments.end(); it != end; ++it ) { if ( !(*it)->OnSaveModified() ) { return false; } } while ( !m_childDocuments.empty() ) { wxDocument * const childDoc = m_childDocuments.front(); if ( !childDoc->Close() ) { wxFAIL_MSG( "Closing the child document unexpectedly failed " "after its OnSaveModified() returned true" ); } childDoc->DeleteAllViews(); } return OnCloseDocument();}bool wxDocument::OnCloseDocument(){ // Tell all views that we‘re about to close NotifyClosing(); DeleteContents(); Modify(false); return true;}
Delete a view
Call wxDocument::DeleteAllViews
to delete all views associated with this document, there are two steps for a view:
- Call
wxView::Close
method to close view;
- Call Delete to delete the View object.
- When more than one view is present, call delete individually
bool Wxdocument::D eleteallviews () {wxdocmanager* manager = Getdocumentmanager (); First check if all views agree to be closed const wxlist::iterator end = M_documentviews.end (); for (Wxlist::iterator i = M_documentviews.begin (); I! = end; ++i) {Wxview *view = (Wxview *) *i; if (!view->close ()) return false; }/agreed to close, now do close them if (M_documentviews.empty ()) {if (Manager && Manager->getdocuments (). Member (this)) delete this; } else//has views {for (;;) {Wxview *view = (Wxview *) *m_documentviews.begin (); BOOL Islastone = m_documentviews.size () = = 1; Delete view; if (islastone) break; }} return true;}
The method of the view class Close
is relatively simple, is to call the user's OnClose
method, of course, OnClose
there is a default implementation, wxView::OnClose
the default implementation is called wxDocument::Close
, the previous article has been described, do not repeat:
bool wxView::Close(bool deleteWindow){ return OnClose(deleteWindow);}bool wxView::OnClose(bool WXUNUSED(deleteWindow)){ return GetDocument() ? GetDocument()->Close() : true;}
We also need to focus on delete view;
this line of statements, which implements the separation of the view from the Doc class, where the final call m_viewDocument->RemoveView
implements the removal of itself from Doc:
wxView::~wxView(){ if (m_viewDocument && GetDocumentManager()) GetDocumentManager()->ActivateView(this, false); if ( m_docChildFrame && m_docChildFrame->GetView() == this ) { m_docChildFrame->SetView(NULL); m_docChildFrame->GetWindow()->Destroy(); } if ( m_viewDocument ) m_viewDocument->RemoveView(this);}
Delete a Document object
Trace wxDocument::RemoveView
, you can see that the view is removed from the doc's m_documentViews
list and then called OnChangedViewList
for post-processing to check that the OnChangedViewList
current doc is not associated with any view and will initiate its own deletion delete this
.
bool wxDocument::RemoveView(wxView *view){ (void)m_documentViews.DeleteObject(view); OnChangedViewList(); return true;}void wxDocument::OnChangedViewList(){ if ( m_documentViews.empty() && OnSaveModified() ) delete this;}
Close Frame
In the previous article we saw that the closing of the Doc object was a dynamically registered handler, and since it was called in the wxDocParentFrameAny<>::OnCloseWindow
method, event.Skip()
the message would continue to be passed, and then continue to look for the static message table, as we can see in the wxTopLevelWindowBase
following definition:
BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) EVT_SIZE(wxTopLevelWindowBase::OnSize)END_EVENT_TABLE()
At this point, the processing of the static message processing table continues, and the corresponding processing entry message is wxTopLevelWindowBase::OnCloseWindow
:
- Add yourself to the
wxPendingDelete
queue so that the next time you idle will be deleted;
- Hide the window you want to delete;
void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)){ Destroy();}bool wxTopLevelWindowBase::Destroy(){ if ( wxWindow* parent = GetParent() ) { if ( parent->IsBeingDeleted() ) return wxNonOwnedWindow::Destroy(); } if ( !wxPendingDelete.Member(this) ) wxPendingDelete.Append(this); for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(), end = wxTopLevelWindows.end(); i != end; ++i ) { wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i); if ( win != this && win->IsShown() ) { Hide(); break; } } return true;}
App cleanup
Again, we look at the cleanup of the app class, the App class start-up process can refer to the Start Code section, here back to the call point wxEntryReal
, the execution of the program will be returned from the, that is, wxTheApp->OnRun()
exit Wxtry scope, we have to focus on CallOnExit
the role:
When defining CallOnExit
a class, an object is created together, and callOnExit
this object is on the stack, so when you exit the scope of the wxtry, you are bound to call the destructor of this object, the reference definition, and we see that the destructor is finally called wxTheApp->OnExit()
.
This invokes the FANGF of the app class through the temporary object's destructor OnExit
int wxEntryReal(int& argc, wxChar **argv){ wxInitializer initializer(argc, argv); if ( !initializer.IsOk() ) { return -1; } wxTRY { if ( !wxTheApp->CallOnInit() ) { return -1; } // ensure that OnExit() is called if OnInit() had succeeded class CallOnExit { public: ~CallOnExit() { wxTheApp->OnExit(); } } callOnExit; WX_SUPPRESS_UNUSED_WARN(callOnExit); return wxTheApp->OnRun(); } wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )}
Multiple closed multi-document parent window close
The parent window of the Multiple file window is used to hold one or more child windows, closing the process with the Wxframe normal shutdown process.
How do I notify a child window? Watch Destroy ...
Multiple window closed
In general use, we will close the Sub-window of the multi-document app independently, the process is the user clicked the Close button of the child window frame, the message generation process is similar to the Single document window, we can find the wxDocChildFrameAny<>
class in the CREATE function created in the wxEVT_CLOSE_WINDOW
dynamic binding to the message wxDocChildFrameAny::OnCloseWindow
.
bool Create(wxDocument *doc, ...){ if ( !wxDocChildFrameAnyBase::Create(doc, view, this) ) return false; if ( !BaseClass::Create(parent, id, title, pos, size, style, name) ) return false; this->Connect(wxEVT_ACTIVATE, wxActivateEventHandler(wxDocChildFrameAny::OnActivate)); this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxDocChildFrameAny::OnCloseWindow)); return true;}
OnCloseWindow
The invocation of the method is simple, and we see the implementation one by one:
// wxDocChildFrameAny < > void OnCloseWindow(wxCloseEvent& event){ if ( CloseView(event) ) Destroy(); //else: vetoed}
wxDocChildFrameAnyBase::CloseView
To close the view and call the view Close
method, we know that the view will call the Doc method again when it is closed, so that the Close
views and document objects are closed.
Deleting the view after closing is done, the document is called again in the destructor for deleting the view, and the document RemoveView
deletes itself when the document object checks to the view object that it does not have associated with it.
The view and the document have been deleted.
bool wxDocChildFrameAnyBase::CloseView(wxCloseEvent& event){ if ( m_childView ) { if ( !m_childView->Close(false) && event.CanVeto() ) { event.Veto(); return false; } m_childView->Activate(false); m_childView->SetDocChildFrame(NULL); wxDELETE(m_childView); } m_childDocument = NULL; return true;}
Continue to see the wxDocChildFrameAny<>::Destroy
method, this method will call the parent class implementation Destroy
, the call Destroy
method will destroy the window, with the normal window destroyed.
// wxDocChildFrameAny < > virtual bool Destroy(){ // FIXME: why exactly do we do this? to avoid activation events during // destructions maybe? m_childView = NULL; return BaseClass::Destroy();}
Let's focus on when the Subwindow is out of relationship with the parent window. wxMDIChildFrame
Destructors found:
- Call
GetMDIParent()->RemoveMDIChild
method to restore the original menu of the parent class;
- Call
MSWDestroyWindow
to detach itself from the parent class window
wxMDIChildFrame::~wxMDIChildFrame(){ // if we hadn‘t been created, there is nothing to destroy if ( !m_hWnd ) return; GetMDIParent()->RemoveMDIChild(this); m_frameToolBar = NULL; m_frameStatusBar = NULL; DestroyChildren(); MDIRemoveWindowMenu(NULL, m_hMenu); MSWDestroyWindow();}
After the window is deleted, the parent window will continue to survive.
Formal deletion of Windows
The method is called when the app is idle, which in wxAppConsoleBase::ProcessIdle
turn calls the DeletePendingObjects
window object to clean up for deletion.
The operation process is wxPendingDelete
to get all the objects to be deleted from the, delete out.
bool wxAppConsoleBase::ProcessIdle(){ // synthesize an idle event and check if more of them are needed wxIdleEvent event; event.SetEventObject(this); ProcessEvent(event);// Garbage collect all objects previously scheduled for destruction. DeletePendingObjects(); return event.MoreRequested();}void wxAppConsoleBase::DeletePendingObjects(){ wxList::compatibility_iterator node = wxPendingDelete.GetFirst(); while (node) { wxObject *obj = node->GetData(); if ( wxPendingDelete.Member(obj) ) wxPendingDelete.Erase(node); delete obj; node = wxPendingDelete.GetFirst(); }}
Summary of window closing process
The following is a summary of when the user can capture the shutdown, the user can intercept this message by the following method.
type |
methods for user overloading |
Wxapp |
virtual int OnExit () |
Wxdocument |
virtual bool OnCloseDocument () |
Wxview |
virtual bool OnClose (bool Deletewindow) |
Wxframe |
virtual bool Destroy ()//overload must call the method of the parent class |
How to manually delete a view
From the above analysis, we see that before deleting the view, we need to call wxView::Close
the method first, and then call the user's
OnClose
method, and then delete the drop.
void deleteView(wxView *view){ view->Close(); delete view}
Wxwidgets Source Analysis (6)-Window closing process