【问题标题】:Avoid wxFrame destroy when closing关闭时避免 wxFrame 销毁
【发布时间】:2012-11-29 14:35:35
【问题描述】:

我想创建在关闭时不会被销毁的 wxFrame,所以我可以稍后将它们显示回来,并且即使它们被隐藏也可以继续更新它们。

我尝试使用SetExtraStyle(wxWS_EX_BLOCK_EVENTS) 跳跃,因为它不会将 wxCloseEvent 传播给曾经破坏它的人,但它没有帮助。

我找到了以下解决方案。我必须创建一个处理程序来处理关闭事件并隐藏框架。在这种情况下,事件不会被进一步传播。 但这有点重,因为我需要跟踪处理程序并自己删除它。

有人有更聪明的解决方案吗?

    class FrameCloseHider
        : public wxEvtHandler
      {
      public:
        explicit FrameCloseHider(wxTopLevelWindow*);
        void internalOnQuit(wxCloseEvent&);
        wxTopLevelWindow* getFrame();
      private:
        wxTopLevelWindow*   frame_;
      };

     wxTopLevelWindow* FrameCloseHider::getFrame()
      {
        return this->frame_;
      }

      void FrameCloseHider::internalOnQuit(wxCloseEvent& obj)
      {
         this->frame_->Hide();
       }  

      FrameCloseHider::FrameCloseHider(wxTopLevelWindow* frame)
        :frame_(frame)
      {
        this->frame_->Connect(
          frame_->GetId(),
          wxEVT_CLOSE_WINDOW,
          wxCloseEventHandler(FrameCloseHider::internalOnQuit),
          NULL,
          this);
      }

【问题讨论】:

  • 您确定要保留窗口,而不是将要继续更新的特定数据分离到另一个类中吗? (就像文档/视图分离...) 让操作系统窗口保持在周围但不可见是一种奇怪的优化,您在程序中执行的此类操作越多,它就越令人困惑。
  • 为什么不能从 wxFrame 派生并将事件处理程序放在派生类中?
  • @Pete:我认为继承添加这样的功能没有意义,因为我可能希望拥有很多不同的功能并为它们中的每一个继承......根本不可能。
  • @HostileFork:你有关于这个文档/视图分离的好的文档吗?也许停止更新是一种优化,但销毁窗口并创建一个新窗口有点复杂。我正在开发的应用程序是多线程的,并且在 UI 线程和生成数据的其他线程中进行初始化很痛苦。
  • 我看不出它会如何改变任何东西,因为除了在几乎大多数操作系统上创建 GUI 的线程之外,你真的不应该从任何东西进行 GUI 调用。我想这适用于显示和隐藏(尽管它是否会崩溃或挂起或导致不良行为可能取决于具体情况)。您应该寻找工作人员/GUI 分离的良好示例,工作人员可以将请求排队到 GUI 管道。 Qt 有一个great cross-thread messaging system,所以一定要考虑切换...! :-)

标签: c++ wxwidgets


【解决方案1】:

如果你看一下wxEvtHandler源代码,你会发现如果你提供用户数据来连接,那么在连接被破坏时它会被删除。

因此,在您的示例中,由于 wxEvtHandler 继承自 wxObject,您应该可以这样做:

this->frame_->Connect(
  frame_->GetId(),
  wxEVT_CLOSE_WINDOW,
  wxCloseEventHandler(FrameCloseHider::internalOnQuit),
  this, // ** Use the event handler as the user data.
  this);

现在,由于您想确保它只在堆上创建,请将 FrameCloseHider 的构造函数设为私有并添加一个静态函数来建立连接:

public:
    static void ConnectTo(wxTopLevelWindow* frame) {
        FrameCloseHider* obj = new FrameCloseHider(frame);
        frame->Connect(
          frame->GetId(),
          wxEVT_CLOSE_WINDOW,
          wxCloseEventHandler(FrameCloseHider::internalOnQuit),
          obj,
          obj);
    }
private:
      FrameCloseHider::FrameCloseHider(wxTopLevelWindow* frame)
        :frame_(frame)
      {
      }

[注意:您可能应该通过使用 auto_ptr 并在连接调用后释放它来使这个异常安全] 您需要进行测试以确保对连接中的用户数据使用事件处理程序不会使其崩溃。从 wx 代码看起来应该没问题,但它是 wx 更复杂的方面之一,如果不花更多我没有的时间就很难确定。

您可以使用一些模板等使其更通用。我已经做到了这一点,但使用了一个稍微不同的模式和一个不作为用户数据传递但有一个单独的对象来处理事件的单例事件处理程序。

【讨论】:

  • 我没有查看源代码,但从文档中不清楚谁拥有用户数据。我也试过你的想法,~FrameCloseHider 永远不会被调用...
  • 如果框架被删除应该是。尝试进入你的 wxFrame 析构函数,看看在通过它的基类 wxEvtHandler dtor 时会发生什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 2013-12-02
  • 2010-10-31
  • 1970-01-01
  • 2010-12-04
  • 2019-03-03
  • 1970-01-01
相关资源
最近更新 更多