如何在回调函数中解析多个 GtkWidget?

huangapple go评论60阅读模式
英文:

How do I parse multiple GtkWidgets in a callback function?

问题

以下是您要的翻译:

我有**两个 GtkWidgets**,我想在**回调函数内部**访问它们

        // (在 activate 函数中)
        GtkWidget *input;
        GtkWidget *output;
        input = gtk_entry_new();
        output = gtk_entry_new();
所以我创建了一个包含对每个小部件指针的**全局结构**

    struct io_entries {
        GtkWidget *input_field;
        GtkWidget *output_field;
    };
然后,我在主函数中创建一个动态分配的结构,以便我可以将其连接到回调函数

        // (在 activate 函数中)
        struct io_entries *data = malloc(sizeof(struct io_entries));
        data->input_field = input;
        data->output_field = output;
        
        g_signal_connect(button, "clicked", G_CALLBACK(my_function), data);
        free(data);

最后,我**调整回调函数的参数**,以便我可以访问结构内的数据:

    static void my_function(GtkWidget *widget, struct io_entries *data) {
        // 现在我可以使用 data->input_field 访问输入和输出输入小部件
        unsigned int input_length = (guint)gtk_entry_get_text_length(GTK_ENTRY(data->input_field));

        // ...
    }
由于某种我业余技能看不到的明显原因,这会导致未定义的行为,程序通常会正常编译并运行得很好,但在每 5 次运行中会随机崩溃,即使输入数据相同,有时会出现 Windows 错误代码,或者有时会创建 GTK 警告:

> GLib-GObject-WARNING **: 13:59:11.034: 在将其强制转换为 'GtkEntry' 时出现无效的未分类指针。

**所以我的问题是,我做错了什么?**

是因为我*更改了* **my_function(GtkWidget *widget, gpointer data)** *标准签名*吗?(因为如果我不这样做,它就不允许我编译。)

还是我*错误地进行了转换*,使用了 **GTK_ENTRY(data->input_field)**

另外,我是否可以避免使用全局结构?

非常感谢您的提前回答。



**编辑:** 我忘了在主函数中只有:
```c
int main(int argc, char **argv) {
    GtkApplication *app;
    int status;

    app = gtk_application_new("example.com", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    printf("程序已结束\n");
    g_object_unref(app);

    return status;
}

所以根据我得到的答案,解决方案将是创建一个指向该结构的全局指针:

struct io_entries *io_entries_pointer;

在 activate 函数中:

    struct io_entries *data = malloc(sizeof(struct io_entries));
    io_entries_pointer = data; // 这样我可以在作用域之外释放它

最后,在主函数中,在 g_application_run() 之后添加以下内容:

free(io_entries_pointer);
英文:

I have two GtkWidgets that I want to have access to when I am inside a call back function

    // (in activate)
GtkWidget *input;
GtkWidget *output;
input = gtk_entry_new();
output = gtk_entry_new();

So what I do is create a global struct that contains a pointer to each widget:

struct io_entries {
GtkWidget *input_field;
GtkWidget *output_field;
};

Then I create a dynamically allocated struct in main so that I can signal connect it to a call back function

    // (in activate)
struct io_entries *data = malloc(sizeof(struct io_entries));
data->input_field = input;
data->output_field = output;
g_signal_connect(button, "clicked", G_CALLBACK (my_function), data);
free(data)

And finally I adjust the arguments of the callback function so that I can access the data inside of the struct:

static void my_function(GtkWidget *widget, struct io_entries *data) {
// Now I can access my input AND output entry widget with data->x_field
unsigned int input_length = (guint)gtk_entry_get_text_length(GTK_ENTRY (data->input_field));
// ...
}

This, for some probably obvious reason that my amateur skills can't see, creates some undefined behavior where the program will compile normally and run perfectly fine but randomly crash out of every 5 runs with identical input data, sometimes giving Windows error codes, or sometimes creating GTK warnings:

> GLib-GObject-WARNING **: 13:59:11.034: invalid unclassed pointer in cast to 'GtkEntry'

So my question is, what am I doing wrong?

Is it that I am changing the standard signature of my_function(GtkWidget *widget, gpointer data)? (because if I don't it doesn't let me compile.)

Is it that I am incorrectly casting with GTK_ENTRY(data->input_field)?

Additionally, can I somehow avoid using a global struct?

Thanks a lot in advance.

.

EDIT: I forgot that in main I only have:

int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("example.com", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run(G_APPLICATION (app), argc, argv);
printf("Program has ended\n");
g_object_unref(app);
return status;
}

So adding to the answer that I got, the solution would be to create a global pointer to that struct:

struct io_entries *io_entries_pointer;

In activate:

    struct io_entries *data = malloc(sizeof(struct io_entries));
io_entries_pointer = data; // So I can free it outside of the scope

And finally in main I would add this after g_application_run():

free(io_entries_pointer);

答案1

得分: 2

你很合理地创建了具有所需字段的结构:

    // (在主函数中)
    struct io_entries *data = malloc(sizeof(struct io_entries));
    data->input_field = input;
    data->output_field = output;
    
    g_signal_connect(button, "clicked", G_CALLBACK(my_function), data);

此时,GTK 已经存储了指针 data 的一个副本。请注意,它没有复制您的结构,只复制了指向它的指针。

然后,您执行了以下操作:

    free(data);

现在,data 是一个无效的指针。调用 malloc() 和类似函数的其他部分很可能会获取您结构所在的内存,并覆盖它。

稍后,您的回调函数被调用,您对无效指针 data 进行解引用。这将导致未定义行为。

解决方案:在确保不再接收任何回调之前(例如,在程序退出之前),不要调用 free(data);

英文:

You are quite reasonably creating your structure with the required fields:

    // (in main)
struct io_entries *data = malloc(sizeof(struct io_entries));
data->input_field = input;
data->output_field = output;
g_signal_connect(button, "clicked", G_CALLBACK (my_function), data);

At this point, GTK has stored a copy of your pointer, data. Note that it has not taken a copy of your structure, only the pointer to it.

You then do this:

    free(data);

Now, data is an invalid pointer. Other things that call malloc() and friends are likely to get the memory that your structure was in, and can overwrite it.

Later, your callback function is called, and you dereference data, which is an invalid pointer. This will invoke Undefined Behaviour.

Solution: do not call free(data); until such a time as you are guaranteed not to get any more callbacks (e.g. just before the program exits).

huangapple
  • 本文由 发表于 2023年2月23日 21:50:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75545708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定