GTK2 +错误:GTK_IS_CONTAINER& GTK_IS_WIDGET失败

时间:2015-07-07 18:19:43

标签: c gtk

这是我在这里的第一篇帖子,我创建了这个帐户是因为我有点难过。 我正在尝试将传递结构作为回调的参数进行练习,为此我在窗口中创建了一个带有按钮的简单程序。在第一次迭代中,按下带有标签“按钮1”的按钮将其更改为带有标签“按钮2”的不同按钮,而在第二次迭代中,通过将鼠标悬停在按钮上来完成更改。 下面是第一次迭代的代码

#include <gtk/gtk.h>

typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example;

void callback_func (GtkWidget *ignored, example *test) {
GtkWidget *window=test->window;
GtkWidget *changebutton1=test->button1;
GtkWidget *changebutton2=test->button2;
gtk_container_remove(GTK_CONTAINER(window),changebutton1);
gtk_container_add(GTK_CONTAINER(window),changebutton2);
gtk_widget_show_all(window);
}
void callback_func2 (GtkWidget *ignored, example *test) {
GtkWidget *window=test->window;
GtkWidget *changebutton1=test->button1;
GtkWidget *changebutton2=test->button2;
gtk_container_remove(GTK_CONTAINER(window),changebutton2);
gtk_container_add(GTK_CONTAINER(window),changebutton1);
gtk_widget_show_all(window);
}

int main(int argc, char *argv[]) {
example test;
gtk_init(&argc,&argv);
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *changebutton1=gtk_button_new_with_label("Button 1");
GtkWidget *changebutton2=gtk_button_new_with_label("Button 2");

test.window=window;
test.button1=changebutton1;
test.button2=changebutton2;

g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);


gtk_container_add(GTK_CONTAINER(window),changebutton1);
g_signal_connect (G_OBJECT (changebutton1), "clicked", G_CALLBACK (callback_func), (gpointer*)&test);
g_signal_connect (G_OBJECT (changebutton2),"clicked",G_CALLBACK(callback_func2),(gpointer*)&test);
gtk_widget_show_all(window);

gtk_main ();
return 0;
}

当运行上面的代码时,通过单击按钮一次,按钮切换正常,但是当我再次单击它时(现在调用callback_func2而不是callback_func,这对于按钮切换位置基本相同)我得到: (gtktesting.exe:92024):Gtk-CRITICAL **:gtk_container_add:断言`GTK_IS_WIDGET(widget)'失败

如果我用“enter_notify_event”和“leave_notify_event”替换“clicked”事件,第一次更改也会失败,现在会产生更多错误。

有人知道发生了什么事吗?

另外,一个奖金问题。我几乎从另一篇文章中复制并粘贴了这段代码的基础,因为我一直试图自己编写它没有成功,我想测试它是否有效。我注意到回调中的第二个参数是“example * test”。任何人都可以解释“示例”类型吗?它只是结构的名称,我不知道它在那里做了什么。

1 个答案:

答案 0 :(得分:1)

<强> TL;博士

尝试:

test.window  = g_object_ref(window);
test.button1 = g_object_ref(changebutton1);
test.button2 = g_object_ref(changebutton2);

完全解释

GTK +中的对象(即GObject的子类)被引用计数。这意味着,每个对象(例如Widget)都有“引用计数” - 指向它的指针数。当数字达到0时 - 对象被取消分配。使用引用计数为1创建对象。由于C没有智能指针C ++也没有类似的东西,引用计数必须手动完成。用户必须调用g_object_ref以保留引用(我可以互换地使用“指针”和“引用”),并在用户完成引用时调用g_object_unref。这确保了在使用时不会破坏任何对象。

GtkWidget很特别,因为它以“浮动”引用开始。这意味着引用第一次小部件时它的引用计数不会增加 - 它的“浮动”引用是“沉没”。之后,它的行为与任何其他GObject一样。

创建按钮时,会使用引用计数1(“浮动”)创建它们。当它们被添加到它们的容器中时,它们的引用仍然是1(但是“沉没”)。这意味着按钮被拥有由容器添加到

现在,当您从容器中删除按钮时:

gtk_container_remove(GTK_CONTAINER(window),changebutton1);

changebutton1的引用计数减少,下降到0,这会强制对象破坏,而test.button1现在正在悬挂指针。

要解决此问题,请在您希望存储指向g_object_ref的指针时随时使用GObject。这样,您就表达了“test参与changebutton1的所有权”(或“test有兴趣让changebutton1保持活着”。

完成windowbutton1button2后,请致电g_object_unref

加分问题

  

另外,一个奖金问题。我几乎复制并粘贴了基础   来自另一篇文章的这段代码,因为我一直试图写出来   我没有成功,我想测试它是否有效。一世   注意到回调中的第二个参数是“example * test”。   任何人都可以解释“示例”类型吗?这只是它的名字   结构,我不知道它在做什么。

example在此处定义:

typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example; // declares type "example"

GObject信号系统的设计方式允许将任意指针作为最后一个参数传递给回调,因此程序员可以从创建信号连接的地方传递额外信息(g_signal_connect) ,回调。