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

GTK3中g_signal_connect_data触发严重错误的排查求助

GTK3适配GTK4 Builder UI文件的问题排查与解决

问题描述

将GTK4入门教程的example-4.c适配为GTK3版本,采用XML格式UI描述文件builder.ui搭配C代码实现,使用编译命令:

gcc `pkg-config --libs --cflags gtk+-3.0` exemple4.c -o hello `pkg-config --libs gtk+-3.0`

运行后主窗口弹出但无内容,反复出现两次错误:

(hello:19840): GLib-GObject-WARNING **: 19:38:31.985: invalid (NULL) pointer instance

(hello:19840): GLib-GObject-CRITICAL **: 19:38:31.985: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

原代码文件

exemple4.c

#include <gtk-3.0/gtk/gtk.h>
#include <glib/gstdio.h>

static void
print_hello (GtkWidget *widget,
             gpointer   data)
{
  g_print ("Hello World
");
}

static void
quit_cb (GtkWindow *window)
{
  gtk_window_close (window);
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkBuilder *builder = gtk_builder_new ();
  gtk_builder_add_from_file (builder, "builder.ui", NULL);

  GObject *window = gtk_builder_get_object (builder, "window");
  gtk_window_set_application (GTK_WINDOW (window), app);

  GObject *button = gtk_builder_get_object (builder, "button1");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  button = gtk_builder_get_object (builder, "button2");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  button = gtk_builder_get_object (builder, "quit");
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (quit_cb), window);

  gtk_widget_show (GTK_WIDGET (window));

  g_object_unref (builder);
}

int
main (int   argc,
      char *argv[])
{
#ifdef GTK_SRCDIR
  g_chdir (GTK_SRCDIR);
#endif

  GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);

  int status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

builder.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object id="window" class="GtkWindow">
    <property name="title">Grid</property>
    <child>
      <object id="grid" class="GtkGrid">
        <child>
          <object id="button1" class="GtkButton">
            <property name="label">Button 1</property>
            <layout>
              <property name="column">0</property>
              <property name="row">0</property>
            </layout>
          </object>
        </child>
        <child>
          <object id="button2" class="GtkButton">
            <property name="label">Button 2</property>
            <layout>
              <property name="column">1</property>
              <property name="row">0</property>
            </layout>
          </object>
        </child>
        <child>
          <object id="quit" class="GtkButton">
            <property name="label">Quit</property>
            <layout>
              <property name="column">0</property>
              <property name="row">1</property>
              <property name="column-span">2</property>
            </layout>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

问题原因分析

  1. UI布局语法不兼容:GTK4中GtkGrid的子控件布局使用<layout>标签,但GTK3不支持该标签,导致UI文件加载失败,所有控件对象(包括按钮)返回NULL,触发信号连接的断言错误,窗口无内容。
  2. API版本差异:GTK3没有gtk_window_close()函数,该函数是GTK4新增,调用会导致未定义行为。
  3. 代码小问题:g_print中的换行符未正确转义,会引发编译警告;仅调用gtk_widget_show()无法确保子控件全部显示。
  4. 编译命令冗余:重复添加pkg-config --libs gtk+-3.0参数,虽不影响编译但无必要。

解决办法

1. 修改builder.ui适配GTK3语法

将<layout>标签替换为GTK3支持的<packing>标签,指定GtkGrid的行列位置:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object id="window" class="GtkWindow">
    <property name="title">Grid</property>
    <property name="default-width">300</property>
    <property name="default-height">200</property>
    <child>
      <object id="grid" class="GtkGrid">
        <property name="margin">10</property>
        <property name="row-spacing">10</property>
        <property name="column-spacing">10</property>
        <!-- Button 1 -->
        <child>
          <object id="button1" class="GtkButton">
            <property name="label">Button 1</property>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">0</property>
          </packing>
        </child>
        <!-- Button 2 -->
        <child>
          <object id="button2" class="GtkButton">
            <property name="label">Button 2</property>
          </object>
          <packing>
            <property name="left-attach">1</property>
            <property name="top-attach">0</property>
          </packing>
        </child>
        <!-- Quit Button -->
        <child>
          <object id="quit" class="GtkButton">
            <property name="label">Quit</property>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">1</property>
            <property name="width">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

2. 修改C代码适配GTK3 API

替换不兼容的API,修复换行符,添加错误检查:

#include <gtk-3.0/gtk/gtk.h>
#include <glib/gstdio.h>

static void
print_hello (GtkWidget *widget,
             gpointer   data)
{
  g_print ("Hello World\n"); // 修复换行符
}

static void
quit_cb (GtkWindow *window)
{
  gtk_widget_destroy (GTK_WIDGET (window)); // 替换GTK4的gtk_window_close
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkBuilder *builder = gtk_builder_new ();
  GError *error = NULL;
  // 添加UI文件加载错误检查
  if (!gtk_builder_add_from_file (builder, "builder.ui", &error)) {
    g_printerr("Failed to load UI file: %s\n", error->message);
    g_error_free(error);
    return;
  }

  GObject *window = gtk_builder_get_object (builder, "window");
  if (!window) {
    g_printerr("Failed to get window object\n");
    g_object_unref(builder);
    return;
  }
  gtk_window_set_application (GTK_WINDOW (window), app);

  GObject *button = gtk_builder_get_object (builder, "button1");
  if (button) {
    g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
  }

  button = gtk_builder_get_object (builder, "button2");
  if (button) {
    g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
  }

  button = gtk_builder_get_object (builder, "quit");
  if (button) {
    g_signal_connect_swapped (button, "clicked", G_CALLBACK (quit_cb), window);
  }

  gtk_widget_show_all (GTK_WIDGET (window)); // 确保所有子控件显示

  g_object_unref (builder);
}

int
main (int   argc,
      char *argv[])
{
#ifdef GTK_SRCDIR
  g_chdir (GTK_SRCDIR);
#endif

  GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);

  int status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

3. 优化编译命令

去掉重复的libs参数:

gcc `pkg-config --cflags --libs gtk+-3.0` exemple4.c -o hello

验证效果

编译后运行./hello,主窗口将显示三个按钮:点击Button1/Button2会输出Hello World,点击Quit会关闭窗口,无错误输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:42:49