博客
关于我
wxWidgets源码分析(6) - 窗口关闭过程
阅读量:450 次
发布时间:2019-03-06

本文共 5573 字,大约阅读时间需要 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类提供的。调用过程如下:

  • 创建一个wxEVT_CLOSE_WINDOW消息,传递当前的windowID。
  • 调用当前对象的消息处理函数进行处理。
  • 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方法实现如下:

  • 调用CloseDocuments方法关闭所有文档。
  • 删除所有文档模板。
  • 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方法删除关联的所有视图:

  • 调用每个View的Close方法。
  • 删除所有View对象。
  • 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;
    }

    关闭Frame

    在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清理

    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

    要手工删除View,可以调用以下方法:

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

    通过上述步骤,可以清晰地理解窗口关闭过程,同时掌握如何在不同层次截获和处理窗口关闭事件。

    转载地址:http://toyfz.baihongyu.com/

    你可能感兴趣的文章
    Nginx 常用配置清单
    查看>>
    nginx 常用配置记录
    查看>>
    nginx 开启ssl模块 [emerg] the “ssl“ parameter requires ngx_http_ssl_module in /usr/local/nginx
    查看>>
    Nginx 我们必须知道的那些事
    查看>>
    Nginx 的 proxy_pass 使用简介
    查看>>
    Nginx 的配置文件中的 keepalive 介绍
    查看>>
    Nginx 结合 consul 实现动态负载均衡
    查看>>
    Nginx 负载均衡与权重配置解析
    查看>>
    Nginx 负载均衡详解
    查看>>
    nginx 配置 单页面应用的解决方案
    查看>>
    nginx 配置https(一)—— 自签名证书
    查看>>
    nginx 配置~~~本身就是一个静态资源的服务器
    查看>>
    Nginx 配置清单(一篇够用)
    查看>>
    Nginx 配置解析:从基础到高级应用指南
    查看>>
    nginx+php的搭建
    查看>>
    nginx+tomcat+memcached
    查看>>
    nginx+Tomcat性能监控
    查看>>
    nginx+uwsgi+django
    查看>>
    Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流
    查看>>
    Nginx下配置codeigniter框架方法
    查看>>