本文共 5452 字,大约阅读时间需要 18 分钟。
当用户点击窗口的关闭按钮后,Win32系统会向当前的Frame对象发送WM_CLOSE消息。这个消息会被Frame的MSWWindowProc函数处理。MSWWindowProc函数中,会根据消息类型进行相应的处理。在此处,消息类型为WM_CLOSE。
WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { switch (message) { case WM_CLOSE: // 如果不能关闭,告诉系统我们已经处理了这个消息,否则系统会关闭窗口 processed = !Close(); break; // 其他消息类型的处理... }} Close方法是由wxWindowBase类提供的。调用过程如下:
bool wxWindowBase::Close(bool force) { wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); event.SetEventObject(this); event.SetCanVeto(!force); // 返回false表示窗口没有被关闭(因为应用程序有权否决关闭事件) return HandleWindowEvent(event) && !event.GetVeto();} 继续跟踪wxEVT_CLOSE_WINDOW消息的处理。通过分析Frame窗口的继承关系,可以确定消息处理函数。Frame窗口的继承关系如下:
wxDocParentFrame -> wxDocParentFrameBase (wxDocParentFrameAny < wxFrame> )
从wxDocParentFrameAny模板类中可以看到,Create方法中注册了wxEVT_CLOSE_WINDOW消息的处理函数:
// wxDocParentFrameAny < bool Create(wxDocManager *manager, ...) { // ... this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxDocParentFrameAny::OnCloseWindow)); // ...} OnCloseWindow方法会调用m_docManager的Clear方法来实现关闭。
// wxDocParentFrameAny < void OnCloseWindow(wxCloseEvent &event) { if (m_docManager && !m_docManager->Clear(!event.CanVeto())) { // 用户决定不关闭,撤销事件 event.Veto(); } else { // 跳过事件,父类处理会销毁窗口 event.Skip(); }} 文档管理类wxDocManager的Clear方法实现如下:
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;} CloseDocuments方法的实现:
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;} CloseDocument方法的实现:
bool wxDocManager::CloseDocument(wxDocument *doc, bool force) { if (!doc->Close() && !force) return false; doc->DeleteAllViews(); if (m_docs.Member(doc)) delete doc; return true;} 调用wxDocument::DeleteAllViews方法删除关联的所有视图:
bool wxDocument::DeleteAllViews() { wxDocManager *manager = GetDocumentManager(); // 首先检查所有视图是否同意关闭 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; } // 所有视图同意关闭,开始删除 if (m_documentViews.empty()) { if (manager && manager->GetDocuments().Member(this)) delete this; } else { // 删除所有视图 do { wxView *view = (wxView *)*m_documentViews.begin(); bool isLastOne = m_documentViews.size() == 1; delete view; if (isLastOne) break; } while (true); } return true;} 在wxTopLevelWindowBase中定义的事件表中,EVT_CLOSE消息会被静态处理:
BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) { EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) EVT_SIZE(wxTopLevelWindowBase::OnSize)} OnCloseWindow方法会将窗口加入到待删除队列中,并隐藏窗口。
void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent &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 (*i); if (win != this && win->IsShown()) { Hide(); break; } } return true;} App的启动过程可以参考启动代码部分。程序退出时,wxTheApp->OnRun()返回,进入wxTRY的作用域退出时,CallOnExit对象的析构函数会被调用:
int wxEntryReal(int &argc, wxChar **argv) { wxInitializer initializer(argc, argv); if (!initializer.IsOk()) return -1; wxTRY { if (!wxTheApp->CallOnInit()) return -1; class CallOnExit { ~CallOnExit() { wxTheApp->OnExit(); } } callOnExit; return wxTheApp->OnRun(); } wxCATCH_ALL(wxTheApp->OnUnhandledException(); return -1; )} 多文档窗口的父窗口关闭过程与单文档窗口类似。子窗口的关闭则通过Frame的关闭按钮触发,消息处理类似于单文档窗口。
// wxDocChildFrameAny < bool Create(wxDocument *doc, ...) { // ... this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxDocChildFrameAny::OnCloseWindow)); // ...} OnCloseWindow方法:
void wxDocChildFrameAny::OnCloseWindow(wxCloseEvent &event) { if (CloseView(event)) Destroy();} CloseView方法:
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;} 要手工删除View,可以调用以下方法:
void deleteView(wxView *view) { view->Close(); delete view;} 通过上述步骤,可以清晰地理解窗口关闭过程,同时掌握如何在不同层次截获和处理窗口关闭事件。
转载地址:http://toyfz.baihongyu.com/