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

GTK Box容器与ActionBar运行时错误排查求助

GTK应用移除box2后触发段错误的排查与修复

问题描述

使用两个GTK Box容器和ActionBar组件时,将box2添加到窗口程序可正常运行;但移除gtk_window_set_child(GTK_WINDOW(window), GTK_WIDGET(box2))相关代码后,编译无错误,运行时却出现GLib-GObject及Gtk断言错误,最终触发段错误。重写box2/infoBar相关代码后问题仍未解决。

错误信息

(BIDE:12460): GLib-GObject-CRITICAL **: 22:50:34.898: invalid uninstantiatable type '(null)' in cast to 'GtkWidget'

(BIDE:12460): Gtk-CRITICAL **: 22:50:34.898: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed

(BIDE:12460): Gtk-CRITICAL **: 22:50:34.898: gtk_widget_insert_before: assertion 'GTK_IS_WIDGET (widget)' failed

(BIDE:12460): Gtk-CRITICAL **: 22:50:34.940: gtk_widget_get_visible: assertion 'GTK_IS_WIDGET (widget)' failed

(BIDE:12460): Gtk-CRITICAL **: 22:50:34.940: gtk_widget_child_focus: assertion 'GTK_IS_WIDGET (widget)' failed
Segmentation fault (core dumped)

问题根源

  1. 窗口子部件重复设置:原代码多次调用gtk_window_set_child给主窗口设置子部件,每次调用会替换掉之前的子部件,导致被替换的部件失去父容器引用,后续布局逻辑访问无效空指针。
  2. helpWindow子部件设置错误:gtk_window_set_child仅能给窗口设置一个直接子部件,原代码连续两次给helpWindow设置ytURI和gitURI,第二次调用会覆盖第一次,导致ytURI成为无父部件的悬空部件,触发GTK内部断言错误。
  3. 冗余部件未清理:未使用的box2、infoBar等部件未被正确销毁或关联,导致GTK内部处理时访问失效指针。

修复后的代码

#include <gtk/gtk.h>
#include <pango/pango.h>
#include <stdio.h>

GtkWidget *helpWindow;

static void showWindow() {
    gtk_window_present(GTK_WINDOW(helpWindow));
}

static void activateWindow(GtkApplication *app) {
    // 主窗口初始化
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "BIDE");
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);

    // 帮助窗口初始化
    helpWindow = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(helpWindow), "Help");
    gtk_window_set_default_size(GTK_WINDOW(helpWindow), 400, 300);
    gtk_window_set_hide_on_close(GTK_WINDOW(helpWindow), TRUE);

    // 帮助窗口布局:用Box容纳两个链接按钮
    GtkWidget *helpBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_window_set_child(GTK_WINDOW(helpWindow), helpBox);
    GtkWidget *ytURI = gtk_link_button_new_with_label("https://www.youtube.com/channel/UCvECibTCuY1Txj_DtZTddKQ", "My YouTube");
    GtkWidget *gitURI = gtk_link_button_new_with_label("https://github.com/thatitalianguy08", "My Github");
    gtk_box_append(GTK_BOX(helpBox), ytURI);
    gtk_box_append(GTK_BOX(helpBox), gitURI);

    // 主窗口布局:单个垂直Box容纳顶部ActionBar和滚动窗口
    GtkWidget *mainBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
    gtk_window_set_child(GTK_WINDOW(window), mainBox);

    // 顶部ActionBar
    GtkWidget *topActionBar = gtk_action_bar_new();
    gtk_box_append(GTK_BOX(mainBox), topActionBar);

    // ActionBar标题
    GtkWidget *bideLabel = gtk_label_new(NULL);
    gchar *bideLabelText = g_markup_printf_escaped("<b>BIDE</b>");
    gtk_label_set_markup(GTK_LABEL(bideLabel), bideLabelText);
    g_free(bideLabelText); // 释放动态分配的字符串
    gtk_action_bar_pack_start(GTK_ACTION_BAR(topActionBar), bideLabel);
    gtk_widget_set_size_request(bideLabel, -1, 50);

    // 打开文件夹按钮
    GtkWidget *openFolder = gtk_button_new_with_label("Open Folder");
    gtk_action_bar_pack_start(GTK_ACTION_BAR(topActionBar), openFolder);
    gtk_widget_set_size_request(openFolder, -1, 50);

    // 保存按钮
    GtkWidget *saveButton = gtk_button_new_with_label("Save File");
    gtk_action_bar_pack_start(GTK_ACTION_BAR(topActionBar), saveButton);
    gtk_widget_set_size_request(saveButton, -1, 50);

    // 帮助按钮
    gchar *helpButtonText = g_markup_printf_escaped("<u>HELP</u>");
    GtkWidget *helpLabel = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(helpLabel), helpButtonText);
    g_free(helpButtonText); // 释放动态分配的字符串
    GtkWidget *helpButton = gtk_button_new();
    gtk_button_set_child(GTK_BUTTON(helpButton), helpLabel);
    g_signal_connect_swapped(helpButton, "clicked", G_CALLBACK(showWindow), NULL);
    gtk_widget_set_size_request(helpButton, -1, 50);
    gtk_action_bar_pack_start(GTK_ACTION_BAR(topActionBar), helpButton);

    // 主内容滚动窗口
    GtkWidget *sw = gtk_scrolled_window_new();
    gtk_widget_set_vexpand(sw, TRUE);
    gtk_box_append(GTK_BOX(mainBox), sw);

    // 显示主窗口
    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char *argv[]){
    GtkApplication *app = gtk_application_new("me.lufthor.bide", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activateWindow), NULL);
    int ret = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app); // 释放应用对象
    return ret;
}

修复要点

  • 每个窗口仅调用一次gtk_window_set_child,通过Box容器容纳多个子部件,避免部件被覆盖后成为悬空指针
  • 手动释放g_markup_printf_escaped动态分配的字符串,避免内存泄漏
  • 确保所有部件都正确添加到父容器中,让GTK能正常管理部件生命周期
  • 删除原代码中重复设置窗口子部件、未使用的box2/infoBar等冗余逻辑,消除无效部件引用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 02:15:56