这是我在这里的第一篇文章,我写这个账户是因为我有点困惑。我正在尝试将结构作为参数传递给回调,为此,我创建了一个带有窗口按钮的简单程序。在第一次迭代中,按下标签为"Button 1“的按钮会将其更改为带有标签"Button 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-关键**:gtk_container_add:断言`GTK_IS_WIDGET (小部件)‘失败
如果我将“单击”事件替换为"enter_notify_event“和"leave_notify_event",那么第一个更改也会失败,现在会产生更多错误。
有人知道怎么回事吗?
还有一个额外的问题。我几乎是从另一篇文章中复制和粘贴了这段代码的基础,因为我一直试图自己编写它,但没有成功,我想测试它是否有效。我注意到回调中的第二个参数是“示例*test”。有人能解释一下“示例”类型吗?这只是结构的名字,我不知道它在那里做什么。
发布于 2015-07-07 18:52:36
tl;博士
尝试:
test.window = g_object_ref(window);
test.button1 = g_object_ref(changebutton1);
test.button2 = g_object_ref(changebutton2);全解释
对象(即GObject的子类)在GTK+中进行引用计数。这意味着,每个对象(例如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。
奖金问题
还有一个额外的问题。我几乎是从另一篇文章中复制和粘贴了这段代码的基础,因为我一直试图自己编写它,但没有成功,我想测试它是否有效。我注意到回调中的第二个参数是“示例*test”。有人能解释一下“示例”类型吗?这只是结构的名字,我不知道它在那里做什么。
这里定义了example:
typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example; // declares type "example"GObject信号系统是以sucha的方式设计的,它允许将任意指针作为回调的最后一个参数,因此程序员可以将额外的信息从创建信号连接的地方(g_signal_connect)传递给回调。
https://stackoverflow.com/questions/31276404
复制相似问题