GTK中GTK_IS_WIDGET断言失败求助:复用ComboBox异常
问题场景
为减少gtk_combo_box_text_new()的调用次数,将ComboBox改为全局数组声明复用:
static GtkWidget *apo_combobox[NUM_MPI_MEAS];
在弹窗首次初始化时创建并初始化ComboBox,首次打开弹窗正常,但隐藏后再次打开时,执行gtk_grid_attach触发如下错误:
Gtk-CRITICAL : 10:35:18.106: gtk_grid_attach: assertion 'GTK_IS_WIDGET (child)' failed
异常代码片段:
void init_popup() { if (!j_first_show) { apo_combobox[i] = gtk_combo_box_text_new(); init_combobox(i); // 创建窗口和布局的代码,网格也在此初始化 } for (int i = 0; i < 10; i++) { gtk_grid_attach(GTK_GRID(meas_assign.po_grid), apo_combobox[i], 1, j_track_button_placement, 1, 1); } }
打印apo_combobox元素地址未变化,但断言仍失败。
核心原因
初始化逻辑漏洞:
初始化块中使用了未定义的变量i,仅给数组中某个随机索引的ComboBox赋值,其余元素为全局静态数组默认的NULL。循环执行gtk_grid_attach时,NULL指针无法通过GTK_IS_WIDGET断言,直接触发错误。Widget生命周期错误:
若弹窗隐藏时调用gtk_widget_destroy()而非gtk_widget_hide(),首次创建的网格和ComboBox会被彻底销毁。此时apo_combobox中的指针虽地址未变,但指向的是已被GTK回收的无效内存,不再是有效Widget实例。重复容器关联冲突:
即使ComboBox已正确初始化,若弹窗仅隐藏未销毁,再次调用gtk_grid_attach时,ComboBox仍属于之前的网格容器。GTK不允许一个Widget同时属于多个容器,虽会自动移除原关联,但原网格状态异常时也可能触发断言失败。
修复方案
1. 修正初始化循环
在首次初始化时遍历数组,创建所有ComboBox实例,并标记初始化完成:
void init_popup() { if (!j_first_show) { // 批量创建并初始化所有ComboBox for (int i = 0; i < NUM_MPI_MEAS; i++) { apo_combobox[i] = gtk_combo_box_text_new(); init_combobox(i); } // 创建窗口、网格等布局代码 // 标记为已完成首次初始化 j_first_show = TRUE; } for (int i = 0; i < NUM_MPI_MEAS; i++) { // 先检查Widget有效性 if (GTK_IS_WIDGET(apo_combobox[i])) { // 移除可能存在的父容器关联 GtkWidget *parent = gtk_widget_get_parent(apo_combobox[i]); if (parent != NULL) { gtk_container_remove(GTK_CONTAINER(parent), apo_combobox[i]); } // 调整布局索引(示例中j_track_button_placement需按实际需求偏移) gtk_grid_attach(GTK_GRID(meas_assign.po_grid), apo_combobox[i], 1, j_track_button_placement + i, 1, 1); } } }
2. 正确管理弹窗生命周期
使用gtk_widget_hide()隐藏弹窗,而非gtk_widget_destroy()。这样网格和ComboBox实例会被保留,下次打开时直接复用,避免重复创建或无效指针问题。
3. 添加有效性前置检查
在调用gtk_grid_attach前,始终用GTK_IS_WIDGET()宏验证apo_combobox[i]的有效性,过滤空指针或无效实例。
内容的提问来源于stack exchange,提问作者anon1234

