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

GTK4+C语言:点击按钮无法向Box添加Label问题求助

GTK4按钮点击无响应问题修复

你的代码核心问题是传递给回调函数的widgets是栈上的局部变量:在on_activate函数执行完毕后,栈上的struct MyWidgets widgets会被系统回收释放,当按钮点击触发回调时,访问的是已经失效的内存地址,导致程序无法正常执行逻辑(甚至可能直接崩溃)。

修复步骤

将struct MyWidgets改为动态分配内存,确保在回调触发时内存仍然有效:

  1. 在on_activate中,用g_new动态创建结构体实例(替代栈上的局部变量)
  2. 为窗口添加destroy信号回调,在窗口关闭时释放动态分配的内存,避免内存泄漏

修改后的完整代码

#include <gtk/gtk.h>
#undef main

struct MyWidgets{
  GtkWidget* prompt;
  GtkWidget* box;
};

// 释放结构体内存的回调
void on_window_destroy(gpointer data) {
    struct MyWidgets *widgets = (struct MyWidgets*)data;
    g_free(widgets);
}

void on_button_clicked(GtkButton *button, gpointer data) {
    struct MyWidgets *widgets = (struct MyWidgets*) data;

    GtkEntryBuffer *buffer = gtk_entry_get_buffer((GtkEntry*)widgets->prompt);
    const char *text = gtk_entry_buffer_get_text(buffer);
  
    GtkWidget *output = gtk_label_new(text);
    gtk_widget_set_margin_start(output, 30);

    gtk_box_append((GtkBox*)widgets->box, output);
    // GTK4中新建的widget默认可见,无需手动调用gtk_widget_set_visible
}

static void on_activate (GtkApplication *app) {
    GtkWidget *window = gtk_application_window_new (app);
    gtk_window_set_resizable((GtkWindow*)window, FALSE);
    gtk_window_set_default_size((GtkWindow*)(window), 800, 900);

    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_box_set_homogeneous((GtkBox*)box, FALSE);

    GtkWidget *label = gtk_label_new("Enter ebnf expression :");
    gtk_label_set_xalign((GtkLabel*)label, 0);
    gtk_widget_set_margin_start(label, 30);

    GtkWidget *prompt = gtk_entry_new();
    gtk_widget_set_size_request(prompt, 300, 40);
    gtk_widget_set_margin_start(prompt, 30);
    gtk_widget_set_margin_end(prompt, 30);

    GtkWidget *button = gtk_button_new_with_label ("Submit");
    gtk_button_set_has_frame((GtkButton*)button, TRUE);
    gtk_widget_set_margin_start(button, 300);
    gtk_widget_set_margin_end(button, 300);

    // 动态分配结构体,替代栈上局部变量
    struct MyWidgets *widgets = g_new(struct MyWidgets, 1);
    widgets->box = box;
    widgets->prompt = prompt;

    gtk_box_append((GtkBox*)box, label);
    gtk_box_append((GtkBox*)box, prompt);
    gtk_box_append((GtkBox*)box, button);

    g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), widgets);
    // 绑定窗口销毁信号,释放结构体内存
    g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), widgets);

    gtk_window_set_child(GTK_WINDOW(window), box);
    gtk_window_present (GTK_WINDOW (window));
}

int main(int argc, char **argv) {
    GtkApplication *app = gtk_application_new("org.example.GTKTest", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}

额外说明

  • GTK4中,通过gtk_label_new等函数创建的widget默认是可见状态,不需要手动调用gtk_widget_set_visible(output, TRUE)
  • 动态分配的内存一定要记得在合适的时机释放(比如窗口销毁时),避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:35:54