2013-04-14 2 views
0

Статус кво: У меня есть пользовательский виджет (MyWidget) с окном событий.
Проблема: если я создаю, шоу, а затем, позже, скрыть и уничтожить виджет я получаю следующее сообщение из приложения:gdkmm: как уничтожить окно gdk?

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

Что я узнал: Я ve посмотрел в файле 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); 
} 

ответ

0

Это оказалось, что correctest способ уничтожить окно 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 (метод предполагает, что как утверждение).

к сожалению, у меня не было времени и желания, чтобы добраться до самого дна это и endervour, чтобы понять, почему это было d один так, и какие причины и последствия этот подход имеет. В противном случае я бы предоставил более подробное объяснение.

Вы можете найти официальный пример из руководства 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); 
} 
Смежные вопросы