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)
问题根源
- 窗口子部件重复设置:原代码多次调用
gtk_window_set_child给主窗口设置子部件,每次调用会替换掉之前的子部件,导致被替换的部件失去父容器引用,后续布局逻辑访问无效空指针。 - helpWindow子部件设置错误:
gtk_window_set_child仅能给窗口设置一个直接子部件,原代码连续两次给helpWindow设置ytURI和gitURI,第二次调用会覆盖第一次,导致ytURI成为无父部件的悬空部件,触发GTK内部断言错误。 - 冗余部件未清理:未使用的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
相关产品推荐
相关产品推荐

