如何发射携带GtkEntry内容作为用户数据的自定义GTK信号
实现携带GtkEntry内容的自定义GTK信号
核心思路
由于需要传递两个输入框的内容(用户码+公司码),且不想暴露GtkEntry指针,我们可以通过以下方式实现:
- 定义结构体封装需要传递的登录数据
- 在信号发射时动态分配结构体内存,复制输入框文本到结构体中
- 信号回调函数使用数据后主动释放内存,避免泄漏
具体修改步骤
1. 在login_credentials_screen.h中定义数据结构体
添加结构体声明,让main.c能访问封装的数据:
#ifndef LOGIN_CREDENTIALS_SCREEN_H #define LOGIN_CREDENTIALS_SCREEN_H typedef struct { char *user_code; char *company_code; } LoginCredentials; void init_login_credentials_screen(void); void login_cred_subscribe_login_button_callback(GCallback function); #endif
2. 调整自定义信号的定义
在init_login_credentials_screen函数中,保持信号参数类型为指针(兼容结构体指针):
g_signal_new("login-button-clicked", G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
3. 修改信号发射逻辑(on_login_button_clicked)
获取输入框文本,分配结构体内存并复制文本,最终发射信号传递结构体:
void on_login_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data) { const char *user_text = gtk_entry_get_text(GTK_ENTRY(user_code_entry)); const char *company_text = gtk_entry_get_text(GTK_ENTRY(company_code_entry)); // 分配结构体内存 LoginCredentials *creds = g_new(LoginCredentials, 1); // 复制文本(g_strdup自动分配内存,后续需释放) creds->user_code = g_strdup(user_text); creds->company_code = g_strdup(company_text); // 发射自定义信号,传递封装好的登录数据 g_signal_emit_by_name(widget, "login-button-clicked", creds); }
4. 调整main.c中的回调函数
接收结构体数据,使用后释放内存避免泄漏:
#include <glib.h> #include <gtk/gtk.h> #include "login_credentials_screen.h" void on_button_clicked(GtkWidget *widget, gpointer data); int main(void) { gtk_init(NULL, NULL); // 必须初始化GTK才能运行UI init_login_credentials_screen(); login_cred_subscribe_login_button_callback(G_CALLBACK(on_button_clicked)); gtk_main(); return 0; } void on_button_clicked(GtkWidget *widget, gpointer data) { LoginCredentials *creds = (LoginCredentials*)data; printf("User code: %s\n", creds->user_code); printf("Company code: %s\n", creds->company_code); // 释放内存:先释放字符串,再释放结构体 g_free(creds->user_code); g_free(creds->company_code); g_free(creds); }
5. 修正订阅函数的参数类型
将login_cred_subscribe_login_button_callback的参数改为GTK标准的GCallback类型,更严谨:
void login_cred_subscribe_login_button_callback(GCallback function) { g_signal_connect(gtk_builder_get_object(login_credentials_builder, "login_button"), "login-button-clicked", function, NULL); // 此处NULL为连接时的固定用户数据,我们不需要保持即可 }
关键注意事项
- 内存管理:必须在回调中释放结构体和字符串内存,否则会造成内存泄漏
- GTK初始化:
main函数必须调用gtk_init和gtk_main,否则UI无法启动 - 签名匹配:自定义信号的回调函数签名必须与
g_cclosure_marshal_VOID__POINTER匹配,即void (*)(GtkWidget*, gpointer)
内容的提问来源于stack exchange,提问作者Laura
相关产品推荐
相关产品推荐

