我正在尝试使用相同的user_function回调连接一些小部件。在某些情况下,信号具有不同的签名。
我认为搜索我发现gtk_signal_connect_full。
例如我的代码:
int MyObject::connect()
{
callback_object ....
// Create the callback
int ret = g_signal_connect(instance, "clicked", G_CALLBACK (connect_callback), callback_object);
int ret = g_signal_connect(instance, "button-release-event", G_CALLBACK (connect_callback), callback_object);
// Return handler id
return ret;
}
void MyObject::connect_callback(GObject *passedInstance, gpointer param1, gpointer param2)
{
// Return to st_callback
struct st_callback *callback_object = (struct st_callback *) param2;
if(sizeof(param1) == 0) {
callback_object = (struct st_callback *) param1;
}
}
我可以像这样“抽象”用户功能吗?如果可以的话,如何获取额外的参数,例如GdkEvent或GdkEventButton或gchar,...
编辑 -这个问题是GTK +问题,因为在第一个g_signal_connect中,param1是我的结构。我还可以,我知道我的结构会回退。在第二个g_signal_connect中,param1是一个GdkEventButton。也可以,因为我知道这是要回退的GdkEventButton。但是,如果我不知道param1是我的结构,如果它是GdkEvent,GdkEventButton,gchar或其他所有可能的正弦签名,该怎么做?
编辑2 -我在Closures doc
上找到了此信息闭包允许被调用方获取回调参数的类型,这意味着语言绑定不必为每种回调类型编写单独的粘胶。
对于我要找的东西来说,这看起来很完美,但是我一无所获
编辑3
关于ebassi想法,我需要g_signal_query。我这样做是为了抽象:
1-使用g_signal_query查询信号的参数,设置为我的结构以通过回调user_data传递
2-使用g_cclosure_new_swap和g_signal_connect_closure连接,这会将gpointer user_data设置为第一个参数
3-创建的回调如下:connect_callback(gpointer user_data, ...)
,带有可变参数列表
4-内部回调,使用custom + g_signal_query结果返回我的结构
5-循环到GSignalQuery的param_types中,验证每个基本类型
6-使用正确的类型获取va_arg
用于完成回调的完整代码
// Create gpoint param
struct st_callback *callback_object = (struct st_callback *)malloc(sizeof(struct st_callback));
memset(callback_object, 0, sizeof(struct st_callback));
callback_object->callback_name = callback_name;
callback_object->callback_params = callback_params;
// Get params of signal
GSignalQuery signal_info;
g_signal_query(g_signal_lookup (callback_signal, G_OBJECT_TYPE (instance)), &signal_info);
// Save
callback_object->signal_id = signal_info.signal_id;
callback_object->signal_name = signal_info.signal_name;
callback_object->itype = signal_info.itype;
callback_object->signal_flags = signal_info.signal_flags;
callback_object->return_type = signal_info.return_type;
callback_object->n_params = signal_info.n_params;
callback_object->param_types = signal_info.param_types;
GClosure *closure;
closure = g_cclosure_new_swap (G_CALLBACK (connect_callback), callback_object, NULL);
int ret = g_signal_connect_closure (instance, callback_event, closure, TRUE);
和回调
static bool connect_callback(gpointer user_data, ...)
{
// Return to st_callback
struct st_callback *callback_object = (struct st_callback *) user_data;
// get parameters count
int param_count = callback_object->n_params;
va_list ap;
va_start(ap, param_count);
// loop paramters
for (int i=0; i<param_count; i++) {
switch (G_TYPE_FUNDAMENTAL(callback_object->param_types[i])) {
case G_TYPE_CHAR:
break;
case G_TYPE_UCHAR:
break;
case G_TYPE_STRING:
{
char *path = va_arg(ap, char *);
break;
}
case G_TYPE_OBJECT:
break;
case G_TYPE_POINTER:
break;
case G_TYPE_INTERFACE:
break;
case G_TYPE_PARAM:
break;
case G_TYPE_BOXED:
{
// Example, try to cast correct boxed
GdkEvent *e = va_arg(ap, GdkEvent *);
break;
}
}
}
va_end(ap);
}
需要纠正退货和装箱的情况,但是我可以正常工作
答案 0 :(得分:2)
您不应将相同的函数用于不同类型的回调。某些回调采用不同的参数,而其他回调则具有不同的返回值-例如,在您的示例中,clicked
不返回任何值,而button-press-event
返回布尔值。
如果您需要在不同的信号处理程序中执行通用代码,请编写一个函数,然后从各个处理程序中调用它。