C 语言中的 GTK3:如何正确地将小部件数组作为参数发送给回调函数?

问题描述 投票:0回答:1

描述: 我正在使用 C 语言开发 GTK3 应用程序,并面临代码特定部分的问题。该代码涉及用于“保存”按钮的回调函数 (save_enterprise_website) 和用于为公司网站模板创建自定义表单的函数 (create_Enterprise_form)。

问题: 单击“保存”按钮后,程序遇到问题。回调函数迭代 GTK 小部件(条目)数组,尝试从每个 GtkEntry 中提取文本。但是,出现错误,并打印消息“Element 0 is not a GtkEntry”。随后,程序停止响应。

尝试的解决方案: 代码中有一个注释掉的部分,其中使用类似的循环来检查条目数组的每个元素是否都是 GTK_ENTRY 类型。当取消注释并执行此循环时,它会成功打印所有条目的文本。

请求帮助: 我正在寻求有关解决回调函数问题的指导。我可以采取哪些步骤来确保回调函数正确地从 GtkEntry 小部件中提取文本而不会遇到上述问题?

代码:

// Callback function for the "Save" button
void save_enterprise_website(GtkWidget *button, GtkWidget **entries) {

    for (int i = 0; i < 12; i++) {
        if (GTK_IS_ENTRY(entries[i])) {
            const char *text = gtk_entry_get_text(GTK_ENTRY(entries[i]));
            g_print("%s\n", text);
        } else {
            g_print("Element %d is not a GtkEntry\n", i);
        }
    }
}

// Function to create the customization form for the company website template
GtkWidget *create_Enterprise_form(GtkApplication *app) {
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Enterprise_Website");
    gtk_window_set_default_size(GTK_WINDOW(window), 1280, 720);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *grid = gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(window), grid);

    const char *parameters[] = {
        "Name", "About Us", "Slogan", "Contact",
        "Body Color", "Body Font Family",
        "Header BG Color", "Header Text Color",
        "A Text Color", "Footer BG Color",
        "Footer Text Color", "Hero BG Color"
    };

    // Create an array of widgets to store text entry fields
    GtkWidget *entries[G_N_ELEMENTS(parameters)];

    const char *default_texts[] = {
        "Company Name","A brief description of the company and its history", "A slogan for the company",
        "Address, phone number, contact form, etc.", "#f4f4f4", "Arial, sans-serif", 
        "#333", "#fff", "#fff", "#333", "#fff", "#f4f4f4"
    };

    for (int i = 0; i < G_N_ELEMENTS(parameters); i++) {
        GtkWidget *label = gtk_label_new(parameters[i]);
        GtkWidget *entry = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(entry), default_texts[i]);

        PangoFontDescription *font_desc = pango_font_description_from_string("Sans Bold 14");
        gtk_widget_override_font(label, font_desc);
        gtk_widget_override_font(entry, font_desc);
        pango_font_description_free(font_desc);

        int vertical_spacing = 10;
        gtk_widget_set_margin_bottom(label, vertical_spacing);
        gtk_widget_set_margin_bottom(entry, vertical_spacing);

        // Multiply the width of GtkEntry by 3
        gtk_widget_set_size_request(entry, 3 * gtk_widget_get_allocated_width(entry), -1);

        // Add widgets to GtkGrid with adjustments for font size and vertical space
        gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1);
        gtk_grid_attach(GTK_GRID(grid), entry, 1, i, 1, 1);

        // Store entries in the entries array
        entries[i] = entry;

        //test if every element of the array is og GTK_ENTRY type
        /*
            for (int i = 0; i < 12; i++) {
        if (GTK_IS_ENTRY(entries[i])) {
            const char *text = gtk_entry_get_text(GTK_ENTRY(entries[i]));
            g_print("%s\n", text);
        } else {
            g_print("Element %d is not a GtkEntry\n", i);
        }
    }*/

    }

    GtkWidget *submit_button = gtk_button_new_with_label("Save");
    g_signal_connect(submit_button, "clicked", G_CALLBACK(save_enterprise_website), entries);

    // Add the button to GtkGrid
    gtk_grid_attach(GTK_GRID(grid), submit_button, 1, G_N_ELEMENTS(parameters), 1, 1);

    gtk_widget_set_halign(grid, GTK_ALIGN_CENTER);
    gtk_widget_set_valign(grid, GTK_ALIGN_CENTER);

    return window;
}

c gtk3
1个回答
0
投票

问题在于您在堆栈上声明小部件指针数组,将指针作为回调函数参数传递给该数组,然后从函数返回。一旦函数返回,堆栈上的值就可能发生任何事情;它们通常会被覆盖。回调函数正在接收一个指向“曾经”保存数组的位置的指针,但现在该位置保存了一些随机垃圾。一旦回调函数取消引用该指针,您就处于未定义行为的领域;你的程序可能会崩溃。 要解决此问题,您需要使用 malloc() 或相关函数之一在堆上分配数组。堆上的对象一直保留在那里,直到它们被 free() 释放为止(或者堆被损坏,这是另一类错误。) 指向堆栈上值的指针仅在函数调用时才有效。创建的值仍在运行(有时甚至不在运行,因为 C 也可以让你破坏堆栈......)

因为您不知道(也无法知道——这是未定义的行为)函数返回后堆栈上的值会发生什么,所以您会遇到您所看到的情况:看似不相关的代码更改似乎使它起作用。实际上,发生的情况是随机代码更改造成的,因此在调用回调之前,堆栈上的值不会被覆盖,但您根本不能指望该行为:它可能特定于 UI 的特定时间例如 GTK 队列中的事件。

© www.soinside.com 2019 - 2024. All rights reserved.