You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何发射携带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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:20:17