【问题标题】:How to use parametrized member function of a struct in callback?如何在回调中使用结构的参数化成员函数?
【发布时间】:2020-07-30 18:12:55
【问题描述】:

我有一个类似于下面的结构

struct dc_callback
{ 
    int
    my_configure_event(
        GtkWidget *widget,
        GdkEventConfigure *event,
        struct LoadData *myData)
    {
        ...others

        return TRUE;
    }

    //Parametrized Constructor 
    int
    my_draw(
        GtkWidget *widget,
        cairo_t *cr,
        struct LoadData *myData)
    {
        ...others
        return TRUE;
    }
};

它有两个参数化的成员函数,我打算第 n 次从 g_signal_connect 调用它们。

main(){
    int i;
    dc_callback dc_callback_instance[nth];
    for(i=0;i<nth;i++){
        g_signal_connect(widget_list[i],"draw",G_CALLBACK(dc_callback_instance[i].my_draw),myData);
        g_signal_connect(widget_list[i],"configure-event",G_CALLBACK(dc_callback_instance[i].my_configure_event),myData);
    }
}

但是,在编译期间,我收到有关无效使用成员函数 int dc_callback::my_draw(args) 的错误。它要求我添加 () 但这无法完成,因为 G_CALLBACK 接受没有附加参数的函数名称。

我该怎么做?

【问题讨论】:

  • 回调不是这样工作的,回调是指向函数的指针。如果您需要自定义每个回调的行为,请使用 user_data(在您的情况下为 myData)
  • @Nico238 虽然适用,但回调需要为您想要的每个行为提供一个独特的函数,这可能听起来不寻常,那么这可能是一个错误,这就是为什么我需要通过一个独特的函数使用结构。
  • @JamesGuana 我肯定会理解您所说的“回调需要针对您想要的每个行为的唯一函数”的意思。当您连接回调时,您必须提供一个函数指针( dc_callback_instance[i].my_draw 不是)。您可以通过为每个具有相同功能的 wigdet 提供不同的用户数据来为每个小部件设置不同的行为
  • 嗨,是的,我们这样做了,但它不起作用,它注册了所有小部件的最后一个行为。我认为这是一个错误。我相信你是在这里帮助我们的最佳人选gitlab.gnome.org/GNOME/gnome-system-monitor/merge_requests/…

标签: gtk3 cairo


【解决方案1】:

@0x5453 的答案是正确的,除了 my_draw_cbk 及其调用:应该是

gboolean my_draw_cbk ( GtkWidget *widget,
        cairo_t *cr,
        struct CallbackData *cbData)
{
    cbData->dc_callback_inst.my_draw(widget, cr, cbData->otherData);
    return TRUE;
}

并连接信号:

 // cbData shall be free with g_free when no longer needed
 CallbackData* cbData = g_new(CallbackData, 1); 
 // set the cbData values..
 g_signal_connect(widget_list[i],"draw",G_CALLBACK(my_draw_cb),cbData);

【讨论】:

  • 在信号连接中我应该将myDatadc_callback_instance[i] 放在哪里?
  • 我得到小部件'GtkDrawingArea'的绘图失败:空指针和很多其他的。问题可能出在哪里?
【解决方案2】:

G_CALLBACK 需要一个(非成员)函数指针,而您没有使用正确的语法来传递函数指针。但是,还有一个更大的问题:函数指针和成员函数指针在 C++ 中是不同的概念。您不能将成员函数指针传递给需要标准函数指针的接口。 那么,如何将回调的调用与您的dc_callback 实例相关联?

传统上,在使用 C 风格的 API 时,您必须为回调提供一个免费函数,该函数将您的实例(和任何额外数据)作为 void* 参数。然后在回调中,您可以将void* 转换回原始类型。在您的情况下,这可能类似于:

struct CallbackData {
    dc_callback& dc_callback_inst;
    Foo otherData; // whatever else you need to capture here
};

void my_draw_cb(void* data) { // g_signal_connect might pass more params to cb in addition to data
    CallbackData& cbData = *(CallbackData*)data;
    cbData->dc_callback_inst.my_draw(cbData->otherData);
}

// ...
for(i=0;i<nth;i++){
    CallbackData cbData{dc_callback_instance[i], myData};
    g_signal_connect(widget_list[i],"draw",G_CALLBACK(&my_draw_cb),cbData);
    // ...
}

【讨论】:

  • 我在编译期间收到此错误:无法将“CallbackData”转换为“gpointer”{aka“void*”}
猜你喜欢
  • 2019-04-15
  • 2021-08-23
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
相关资源
最近更新 更多