0

现状: 我有一个带有事件窗口的自定义小部件(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);
}
4

1 回答 1

0

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

我也应该说一些关于Gtk::Widget::realize(). 不像Gtk::Widget::unrealize()你应该Gtk::Widget::realize() 在你的小部件没有GDK 窗口时调用(该方法假定它是一个断言)。

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

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

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

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);
}
于 2013-05-06T06:46:06.693 回答