gdkmm:如何销毁 gdk 窗口?

Posted

技术标签:

【中文标题】gdkmm:如何销毁 gdk 窗口?【英文标题】:gdkmm: how to destroy gdk window? 【发布时间】:2013-04-14 12:22:21 【问题描述】:

现状: 我有一个带有事件窗口的自定义小部件 (MyWidget)。问题:如果我创建、显示然后隐藏和销毁小部件,我会从应用程序收到以下消息:

Gdk-WARNING **: losing last reference to undestroyed window

我发现了什么:我查看了gdkwindow.c 文件,当GDK_WINDOW_DESTROYED(window) == FALSE 时报告了此消息。所以我不明白的是我应该如何正确地销毁我的窗口,以便最终调用gdk_window_destroy() 函数。我认为调用它的最佳位置是 Gdk::~Window() 析构函数。但它是空的。而且gdk_window_destroy()gdkwindow.cc 文件中根本不存在。

on_realize()on_unrealize() 回调如下。

class MyWidget : public Gtk::Widget

...
private:
    Glib::RefPtr<Gdk::Window>   _event_window;
...
;

void Gtk::MyWidget::on_realize()

    GdkWindowAttr       attributes;
    const Allocation    & allocation = get_allocation();

    attributes.event_mask = GDK_BUTTON_PRESS_MASK;

    attributes.x = allocation.get_x();
    attributes.y = allocation.get_y();
    attributes.width = allocation.get_width();
    attributes.height = allocation.get_height();
    attributes.wclass = GDK_INPUT_ONLY;
    attributes.window_type = GDK_WINDOW_CHILD;

    _event_window = Gdk::Window::create(get_parent_window(), &attributes, GDK_WA_X | GDK_WA_Y);
    _event_window->set_user_data(Widget::gobj());

    set_window(get_parent_window());

    set_realized();


void Gtk::MyWidget::on_unrealize()

    _event_window->set_user_data(NULL);
    _event_window.reset();

    set_realized(false);

【问题讨论】:

【参考方案1】:

事实证明,销毁您使用Gdk::Window::create() 创建的 GDK 窗口的最正确方法是......猜猜是什么?在您的自定义小部件的on_unrealize() 方法中调用Gtk::Widget::unrealize(),因为除了其他事情之外,此基本方法为小部件的GDK 窗口调用gdk_window_destroy()。为此,您的小部件 必须 是“窗口化的”(即您应该在构造函数中调用 set_has_window(true); 并在 on_realize() 回调中调用 set_window(&lt;your allocated GDK window&gt;);。非常明显的方法,不是吗?

我还应该谈谈Gtk::Widget::realize()。与Gtk::Widget::unrealize() 不同,您应该调用Gtk::Widget::realize() 如果您的小部件没有 GDK 窗口(该方法假定这是一个断言)。

不幸的是,我没有时间并且希望深入了解它并努力了解这样做的原因以及这种方法的原因和后果。否则我会提供更详细的解释。

您可以从 GTK 的自定义小部件教程中找到官方示例 here。

我的小部件的代码现在看起来像这样:

class MyWidget : public Gtk::Widget

...
private:
    Glib::RefPtr<Gdk::Window>   _event_window;
...
;

void Gtk::MyWidget::on_realize()

    GdkWindowAttr       attributes;
    const Allocation    & allocation = get_allocation();

    attributes.event_mask = GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE;

    attributes.x = allocation.get_x();
    attributes.y = allocation.get_y();
    attributes.width = allocation.get_width();
    attributes.height = allocation.get_height();
    attributes.wclass = GDK_INPUT_OUTPUT;
    attributes.window_type = GDK_WINDOW_CHILD;

    _event_window = Gdk::Window::create(get_parent_window(), &attributes, GDK_WA_X | GDK_WA_Y);
    _event_window->set_user_data(Widget::gobj());

    set_window(_event_window);

    set_realized();


void Gtk::MyWidget::on_unrealize()

    _event_window->set_user_data(NULL);
    _event_window.reset();

    Widget::unrealize();
    // it will call gdk_destroy_window() and
    // set_realized(false);

【讨论】:

以上是关于gdkmm:如何销毁 gdk 窗口?的主要内容,如果未能解决你的问题,请参考以下文章

Duilib中创建子窗口后,子窗口销毁的问题

Java的JFrame怎么销毁啊?

使用输入销毁确认弹出窗口

如何销毁小部件?

完成后销毁 QT QML 窗口

MFC窗口创建销毁消息流程