Wxwidgets Source Analysis (6)-Window closing process

Source: Internet
Author: User
Tags wxwidgets

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;...

CloseThe method is wxWindowBase provided by the class, and the calling procedure is as follows:

    1. Creates a wxEVT_CLOSE_WINDOW message that passes the current Windowid
    2. 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<>::OnCloseWindowWill 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:

    1. Call CloseDocuments Close all documents, this step is critical, close the key path of the document;
    2. 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:

    1. Call the method of the Doc class to Close execute the shutdown;
    2. Call the Doc class DeleteAllViews method to close the view associated with this document;
    3. 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

wxDocManagerThe 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 .

OnCloseDocumentThe 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:

    1. Call wxView::Close method to close view;
    2. Call Delete to delete the View object.
    3. 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 :

    1. Add yourself to the wxPendingDelete queue so that the next time you idle will be deleted;
    2. 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;}

OnCloseWindowThe 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::CloseViewTo 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. wxMDIChildFrameDestructors found:

    1. Call GetMDIParent()->RemoveMDIChild method to restore the original menu of the parent class;
    2. 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
OnClosemethod, and then delete the drop.

void deleteView(wxView *view){    view->Close();    delete view}

Wxwidgets Source Analysis (6)-Window closing process

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.