描述: 我正在使用 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;
}
问题在于您在堆栈上声明小部件指针数组,将指针作为回调函数参数传递给该数组,然后从函数返回。一旦函数返回,堆栈上的值就可能发生任何事情;它们通常会被覆盖。回调函数正在接收一个指向“曾经”保存数组的位置的指针,但现在该位置保存了一些随机垃圾。一旦回调函数取消引用该指针,您就处于未定义行为的领域;你的程序可能会崩溃。 要解决此问题,您需要使用 malloc() 或相关函数之一在堆上分配数组。堆上的对象一直保留在那里,直到它们被 free() 释放为止(或者堆被损坏,这是另一类错误。) 指向堆栈上值的指针仅在函数调用时才有效。创建的值仍在运行(有时甚至不在运行,因为 C 也可以让你破坏堆栈......)
因为您不知道(也无法知道——这是未定义的行为)函数返回后堆栈上的值会发生什么,所以您会遇到您所看到的情况:看似不相关的代码更改似乎使它起作用。实际上,发生的情况是随机代码更改造成的,因此在调用回调之前,堆栈上的值不会被覆盖,但您根本不能指望该行为:它可能特定于 UI 的特定时间例如 GTK 队列中的事件。