[英]Segmentation fault while accessing other GTK widgets in a callback
To access other widgets in a callback, I packed them in a structure defined as follows:为了在回调中访问其他小部件,我将它们打包在一个定义如下的结构中:
typedef struct SettingsModel
{
bool SyncEn;
int DeviceId;
int MeasurementId;
GtkWidget *measurement_type_box;
GtkWidget *sync_switch;
GtkWidget *device_type_box;
} SettingsModel;
The aim is to update the settings when the save button is clicked.目的是在单击保存按钮时更新设置。 The relevant code snippets:
相关代码片段:
static void click_save(GtkButton *self, gpointer user_data)
{
SettingsModel *local_data = user_data;
local_data->DeviceId = gtk_combo_box_get_active(GTK_COMBO_BOX(local_data->device_type_box));
local_data->MeasurementId = gtk_combo_box_get_active(GTK_COMBO_BOX(local_data->measurement_type_box));
local_data->SyncEn = gtk_switch_get_active(GTK_SWITCH(local_data->sync_switch));
}
save_settings_button = gtk_button_new_with_label("Save");
reset_settings_button = gtk_button_new_with_label("Reset");
SettingsModel settings;
settings.device_type_box = device_type_box;
settings.measurement_type_box = measurement_type_box;
settings.sync_switch = sync_enabled_switch;
g_signal_connect(save_settings_button, "clicked", G_CALLBACK(click_save), &settings);
g_signal_connect(reset_settings_button, "clicked", G_CALLBACK(click_reset), &settings);
However, when I click on the save button, I receive the following errors:但是,当我单击保存按钮时,我收到以下错误:
(gui:28351): GLib-GObject-WARNING **: 16:52:26.673: invalid cast from 'GdkButtonEvent' to 'GtkComboBox'
(gui:28351): Gtk-CRITICAL **: 16:52:26.673: gtk_combo_box_get_active: assertion 'GTK_IS_COMBO_BOX (combo_box)' failed
zsh: segmentation fault ./gui
It seems that either the structure was initialized wrongly or GTK somehow thinks that the callback should take a GdkButtonEvent?似乎结构初始化错误或 GTK 以某种方式认为回调应该采用 GdkButtonEvent?
Minimal reproducible example here:这里的最小可重复示例:
#include <gtk/gtk.h>
enum
{
COL_ID = 0,
COL_NAME,
NUM_COLS
};
typedef struct SettingsModel
{
bool SyncEn;
int DeviceId;
int MeasurementId;
GtkWidget *measurement_type_box;
GtkWidget *sync_switch;
GtkWidget *device_type_box;
} SettingsModel;
static void click_save(GtkButton *self, gpointer user_data)
{
SettingsModel *local_data = user_data;
local_data->DeviceId = gtk_combo_box_get_active(GTK_COMBO_BOX(local_data->device_type_box));
local_data->MeasurementId = gtk_combo_box_get_active(GTK_COMBO_BOX(local_data->measurement_type_box));
local_data->SyncEn = gtk_switch_get_active(GTK_SWITCH(local_data->sync_switch));
}
static void click_reset(GtkButton *btn_reset, gpointer user_data)
{
SettingsModel *local_data = user_data;
local_data->DeviceId = 0;
local_data->MeasurementId = 0;
local_data->SyncEn = false;
gtk_switch_set_active(GTK_SWITCH(local_data->sync_switch), FALSE);
gtk_combo_box_set_active(GTK_COMBO_BOX(local_data->device_type_box), 0);
gtk_combo_box_set_active(GTK_COMBO_BOX(local_data->measurement_type_box), 0);
}
static void app_activate(GApplication *app, gpointer *user_data)
{
GtkWidget *win;
GtkWidget *grid;
g_assert(GTK_IS_APPLICATION(app));
win = gtk_application_window_new(GTK_APPLICATION(app));
grid = gtk_grid_new();
GtkWidget *device_type_box;
GtkWidget *measurement_type_box;
GtkWidget *save_settings_button;
GtkWidget *reset_settings_button;
GtkWidget *sync_enabled_switch;
GtkListStore *list_store_device;
GtkListStore *list_store_measurement;
GtkCellRenderer *column;
list_store_device = gtk_list_store_new(NUM_COLS, G_TYPE_INT, G_TYPE_STRING);
gtk_list_store_insert_with_values(list_store_device, NULL, -1, COL_ID, 0, COL_NAME, "foo", -1);
device_type_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list_store_device));
g_object_unref(list_store_device);
column = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(device_type_box), column, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(device_type_box), column,
"text", 1,
NULL);
gtk_combo_box_set_active(GTK_COMBO_BOX(device_type_box), 0);
list_store_measurement = gtk_list_store_new(NUM_COLS, G_TYPE_INT, G_TYPE_STRING);
gtk_list_store_insert_with_values(list_store_measurement, NULL, -1, COL_ID, 0, COL_NAME, "foo", -1);
gtk_list_store_insert_with_values(list_store_measurement, NULL, -1, COL_ID, 0, COL_NAME, "bar", -1);
gtk_list_store_insert_with_values(list_store_measurement, NULL, -1, COL_ID, 0, COL_NAME, "something", -1);
measurement_type_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list_store_measurement));
g_object_unref(list_store_measurement);
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(measurement_type_box), column, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(measurement_type_box), column,
"text", 1,
NULL);
gtk_combo_box_set_active(GTK_COMBO_BOX(measurement_type_box), 2);
save_settings_button = gtk_button_new_with_label("Save");
reset_settings_button = gtk_button_new_with_label("Reset");
sync_enabled_switch = gtk_switch_new();
SettingsModel settings;
settings.device_type_box = device_type_box;
settings.measurement_type_box = measurement_type_box;
settings.sync_switch = sync_enabled_switch;
g_signal_connect(save_settings_button, "clicked", G_CALLBACK(click_save), &settings);
g_signal_connect(reset_settings_button, "clicked", G_CALLBACK(click_reset), &settings);
gtk_grid_attach(GTK_GRID(grid), device_type_box, 1, 1, 1, 1);
gtk_grid_attach(GTK_GRID(grid), measurement_type_box, 1, 2, 1, 1);
gtk_grid_attach(GTK_GRID(grid), sync_enabled_switch, 1, 3, 1, 1);
gtk_grid_attach(GTK_GRID(grid), reset_settings_button, 4, 4, 1, 1);
gtk_grid_attach(GTK_GRID(grid), save_settings_button, 5, 4, 1, 1);
gtk_window_set_child(GTK_WINDOW(win), grid);
gtk_widget_show(win);
}
int main (int argc, char **argv) {
GtkApplication *app;
int stat;
app = gtk_application_new("simon.app", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
stat = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}
You are accessing illegal memory because you are passing the address of a non-static object to your callback:您正在访问非法 memory 因为您将非静态 object 的地址传递给您的回调:
static void app_activate(GApplication *app, gpointer *user_data)
{
...
SettingsModel settings;
g_signal_connect(save_settings_button, "clicked", G_CALLBACK(click_save), &settings);
g_signal_connect(reset_settings_button, "clicked", G_CALLBACK(click_reset), &settings);
...
}
When your signal handlers are called, the function app_activate
has already returned to the caller and settings
is no longer valid.当您的信号处理程序被调用时,function
app_activate
已经返回给调用者并且settings
不再有效。 You must provide address of some static memory object or you need to dynamically allocate memory for your settings.您必须提供一些 static memory object 的地址,否则您需要为您的设置动态分配 ZCD69B4957F0980818DZBF3E2。
I would suggest to change definition of settings
to static SettingsModel settings;
我建议将
settings
定义更改为static SettingsModel settings;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.