You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 在代码开头添加自定义回调:
static void on_quit_activate(GtkMenuItem *item, gpointer user_data)
{
  // 将用户数据转换为GApplication实例
  GApplication *app = G_APPLICATION(user_data);
  g_application_quit(app);
}
  1. 修改信号连接代码:
g_signal_connect(quitMi, "activate", G_CALLBACK(on_quit_activate), app);

两种方法都能解决断言错误,实现菜单项点击退出应用的功能。


内容的提问来源于stack exchange,提问作者amdixon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:06:02