c - 如何使用回调修改 GtkWidget 数组的元素

标签 c arrays struct callback gtk

我需要编写一个回调来更改存储在 GtkWidget 数组中的标签的字体颜色。

当前状态的代码在这里 https://github.com/dustynine/colta-gtk/blob/struct/src/main.c

在初始化接口(interface)的函数中,我的数组如下所示:

GtkWidget *cells[CELLS];
for (int i=0; i<CELLS; i++) {
    cells[i] = gtk_label_new("██");
}

连接到按钮的回调:

g_signal_connect(
    G_OBJECT(button),
    "clicked",
    G_CALLBACK(encode),
    make_data(plaintext, key, cells)
);

make_data() 是一个返回带有回调参数的结构的函数:

struct passed_widgets {
    GtkWidget *plaintext;
    GtkWidget *key;
    GtkWidget **cls;
};

gpointer make_data(GtkWidget *text, GtkWidget *key, GtkWidget *cells[CELLS]) {
    static struct passed_widgets pw;
    pw.plaintext = text;
    pw.key = key;
    pw.cls = cells;
    return (gpointer) &pw;
}

在回调本身内部我有这个:

static void encode(GtkButton *button, gpointer *data) {
    struct passed_widgets *pw;
    GdkColor color;
    pw = (struct passed_widgets *) data;

    gdk_color_parse("#07d9d9", &color);
    gtk_widget_modify_fg(GTK_WIDGET(pw -> cls[0]), GTK_STATE_NORMAL, &color);
}

编译器没有提示(除了颜色相关内容已被弃用的警告之外)但是当我实际按下按钮时 Gtk 报告:

(colta-gtk:3993): GLib-GObject-WARNING **: invalid uninstantiatable type 'GInterface' in cast to 'GtkWidget'
(colta-gtk:3993): Gtk-CRITICAL **: gtk_widget_modify_fg: assertion 'GTK_IS_WIDGET (widget)' failed

我在 gdb 中挑选了一下,根据 explore pw -> cls[0]:

'pw -> cls[0]' is a pointer to a value of type 'GtkWidget'

那么,我该如何使它按预期工作呢?我怀疑我要么错误地将数组分配给结构(但这是程序工作的唯一方式),要么在回调结束时尝试修改它时错误地访问它。


编辑: 我按照 liberforce 的建议重写了程序。为我的图形用户界面创建了一个结构:

struct template {
    GtkWidget *window;
    ...
    GtkWidget *plaintext;
    GtkWidget *cells[CELLS];
};

现在我只是将这个我实例化为 gui 的结构传递给回调:

g_signal_connect(
    G_OBJECT(gui.button),
    "clicked",
    G_CALLBACK(encode),
    &gui
);

但是我再也无法在 encode() 函数中使用任何东西了:

static void encode(GtkButton *button, gpointer data) {
    gchar *plaintext;
    struct template *pw;

    pw = (struct template *) data;

    plaintext = gtk_entry_get_text(GTK_ENTRY(pw -> plaintext));
    printf("   plaintext contents: %s\n", plaintext);

我又一次不明白哪里出了问题。编译器没有发出警告,根据 gdb 类型匹配,但是当我运行程序并使用回调时,它给我:

(colta-gtk:21589): Gtk-CRITICAL **: gtk_entry_get_buffer: assertion 'GTK_IS_ENTRY (entry)' failed

(colta-gtk:21589): Gtk-CRITICAL **: gtk_entry_buffer_get_text: assertion 'GTK_IS_ENTRY_BUFFER (buffer)' failed

地址如下:

gui.plaintext address: 0x55babcfc6290
gui address: 0x7ffd13fe8a88
&gui address: 0x7ffd13fe8910
data address: 0x7ffd13fe8910
pw address: 0x7ffd13fe8910
*pw address: 0x7ffd13fe8a88
pw -> plaintext address: (nil)

*pw -> plaintext 导致 Segmentation fault

最佳答案

我想我明白了。我在 main()

之外创建结构原型(prototype)
struct template {
    GtkWidget *window;
    ...
    GtkWidget *plaintext;
    GtkWidget *cells[CELLS];
};

然后在应用程序的“激活”信号上调用的回调中,我这样做:

static void activate(GtkApplication* app, gpointer user_data) {
    static struct template gui;

    gui.plaintext = gtk_entry_new();
    printf("gui.plaintext address: %p\n", gui.plaintext);

    g_signal_connect(
        G_OBJECT(gui.button),
        "clicked",
        G_CALLBACK(encode),
        &gui
    );

在编码回调中我有这个

static void encode(GtkButton *button, gpointer data) {
    gchar *plaintext;
    struct template *pw;

    pw = (struct template *) data;

    plaintext = gtk_entry_get_text(GTK_ENTRY(pw -> plaintext));
    printf("   plaintext contents: %s\n", plaintext);

    GdkColor color;
    gdk_color_parse("#ff0000", &color);
    gtk_widget_modify_fg(GTK_WIDGET(pw -> cells[0]), GTK_STATE_NORMAL, 
    &color);
}

现在一切正常。基本上,我通过将 static 添加到 activate 回调中的 struct template gui 声明来解决我的问题。我将在 github 上保留该文件的工作版本的链接以供将来引用。感谢 liberforce 为我指明了正确的方向。

关于c - 如何使用回调修改 GtkWidget 数组的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47185272/

相关文章:

c - 取消对指针的引用

arrays - 如何根据相邻元素的条件将数组拆分为有限数量的分区

c - free 是否会从较小的结构指针中释放较大结构指针的所有内存?

c++ - 如何为具有共享指针的结构的多索引制作修饰符以 boost 记录器后端以重置此后端?

c - 处理指向数组的指针时发现意外行为

c - 编译时类型不完整,类型已经定义

c - 对不同结构类型的指针进行类型转换是否合法(例如,将 struct sockaddr * 转换为 struct sockaddr_in6 *)?

c - gdb 调试 - 仅在 stdin 内\n

C:将 double 向下舍入为 int 的更好方法

遍历 3D 数组的 Pythonic 方式