简体   繁体   English

在回调中访问其他 GTK 小部件时出现分段错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM