Gtk3通过菜单项调用g_application_quit退出应用失败求助
问题:菜单项调用
g_application_quit无法退出应用,触发GLib-GIO断言错误 尝试通过菜单项调用g_application_quit实现和窗口关闭按钮相同的退出功能,使用的信号连接代码如下:
g_signal_connect(quitMi, "activate", G_CALLBACK(g_application_quit),G_APPLICATION(app));
但运行时出现以下错误,应用无法正常退出:
错误信息
(quit:XXX): GLib-GIO-CRITICAL **: 09:59:42.547: g_application_quit: assertion 'G_IS_APPLICATION (application)' failed
相关完整代码
#include <gtk/gtk.h> static void activate (GtkApplication *app, gpointer user_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *frame; GtkWidget *drawing_area; GtkWidget *menubar; GtkWidget *fileMenu; GtkWidget *fileMi; GtkWidget *quitMi; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "chesstrainer"); gtk_container_set_border_width (GTK_CONTAINER (window), 0); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); menubar = gtk_menu_bar_new(); fileMenu = gtk_menu_new(); fileMi = gtk_menu_item_new_with_label("File"); quitMi = gtk_menu_item_new_with_label("Quit"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMi), fileMenu); gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); // gtk_container_add (GTK_CONTAINER (window), frame); gtk_container_add (GTK_CONTAINER (vbox), frame); g_signal_connect(quitMi, "activate", G_CALLBACK(g_application_quit),G_APPLICATION(app)); drawing_area = gtk_drawing_area_new (); /* set a minimum size */ gtk_widget_set_size_request (drawing_area, 800, 800); gtk_container_add (GTK_CONTAINER (frame), drawing_area); gtk_widget_show_all (window); } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }
问题原因
断言失败的核心是回调函数参数不匹配:
g_application_quit的函数签名是void g_application_quit(GApplication *application),仅接受一个GApplication类型参数。- 而
g_signal_connect连接activate信号时,回调会默认收到两个参数:第一个是触发信号的控件(这里是quitMi),第二个才是你传递的app。 - 这导致
g_application_quit被调用时,误将quitMi当成GApplication实例,触发G_IS_APPLICATION断言失败。
两种解决方法
方法1:使用g_signal_connect_swapped(更简洁)
g_signal_connect_swapped会交换信号传递给回调的参数顺序,让你传递的app作为第一个参数传给g_application_quit,完美匹配函数签名。
修改信号连接代码为:
g_signal_connect_swapped(quitMi, "activate", G_CALLBACK(g_application_quit), app);
方法2:自定义包装回调函数
如果需要在退出前执行额外逻辑,可以写一个中间函数,忽略多余的控件参数,正确调用g_application_quit:
- 在代码开头添加自定义回调:
static void on_quit_activate(GtkMenuItem *item, gpointer user_data) { // 将用户数据转换为GApplication实例 GApplication *app = G_APPLICATION(user_data); g_application_quit(app); }
- 修改信号连接代码:
g_signal_connect(quitMi, "activate", G_CALLBACK(on_quit_activate), app);
两种方法都能解决断言错误,实现菜单项点击退出应用的功能。
内容的提问来源于stack exchange,提问作者amdixon
相关产品推荐
相关产品推荐

