这是我在这里的第一篇帖子,我创建了这个帐户是因为我有点难过。 我正在尝试将传递结构作为回调的参数进行练习,为此我在窗口中创建了一个带有按钮的简单程序。在第一次迭代中,按下带有标签“按钮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”。任何人都可以解释“示例”类型吗?它只是结构的名称,我不知道它在那里做了什么。
答案 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
保持活着”。
完成window
,button1
和button2
后,请致电g_object_unref
。
加分问题
另外,一个奖金问题。我几乎复制并粘贴了基础 来自另一篇文章的这段代码,因为我一直试图写出来 我没有成功,我想测试它是否有效。一世 注意到回调中的第二个参数是“example * test”。 任何人都可以解释“示例”类型吗?这只是它的名字 结构,我不知道它在做什么。
example
在此处定义:
typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example; // declares type "example"
GObject
信号系统的设计方式允许将任意指针作为最后一个参数传递给回调,因此程序员可以从创建信号连接的地方传递额外信息(g_signal_connect
) ,回调。