处理从较低级别对象引发的事件

时间:2015-07-28 18:59:32

标签: c++ events gtk

我正在使用GTK + 3.0编写C ++程序。无论如何,我认为这个问题可能适用于任何使用事件/信号的框架。

我有一个容器类,比如containerClass和一个子类,比如childClasschildClass对象child包含在containerClass对象container中。

编写child对象以修改某些内容的属性。为此目的,它有GtkEntryGtkButton等等。当我单击“保存按钮”时,会引发一个事件。

此事件必须由container对象处理,因为container在某种程度上与数据库接口。

此后,您会找到我正在使用的解决方案:

// Child class
class childClass {

    void setClickHandler_External(void (*extFun)(string property), void *);
    void (*clickHandler_External)(string, void *);  
    void *clickHandler_External_Data;   

    static void buttonClicked(GtkWidget *widget, void *data);
}

void childClass::setClickHandler_External(void (*extFun)(string), void *data) {

    // Set the external event handler
    clickHandler_External = extFun;
    clickHandler_External_Data = data;
}

void childClass::buttonClicked(GtkWidget *widget, void *data) {
    childClass *m = (childClass *)data;

    // Call the external event handler
    m->clickHandler_External(property, m->clickHandler_External_Data);
}

// Container Class
class containerClass {
    childClass child;
    static void clickHandler(string property, void *data);
}

containerClass::containerClass() {
    // Set the event handler
    child.setClickHandler_External((void(*)(string))&(this->clickHandler), (void *)this);
}


void containerClass::clickHandler(string property, void *data) {
    // Event handler in the upper class

    containerClass *m = (containerClass *)data;
    //FINALLY, DO THE JOB WITH PROPERTY!!!
}

这很好用并完成工作。无论如何,我想知道是否有更智能和更清晰的方法来实现相同的目标,可能没有使用指向静态函数的指针,或者通过定义某种类型的模式,每次我需要具有相同的机制时重用。

提前致谢

2 个答案:

答案 0 :(得分:2)

Gtkmm使用sigc ++库来为您处理所有这些。没有必要自己写。

文档链接:

所以,在这种情况下,我会使用像

这样的东西
button.signal_clicked().connect(sigc::mem_fun(container, &containerClass::clickHandler));

同时确保containerClass::clickHander具有适当数量的参数。

答案 1 :(得分:1)

我的第一个建议是使用使用模板来改善你正在做的事情的类型安全性:

template< class ParamType >
void childClass::setClickHandler_External(void (*extFun)(string, ParamType *),
                                          ParamType *data)
{
    // Set the external event handler
    clickHandler_External = (void ()(string,void*))extFun;
    clickHandler_External_Data = (void*)data;
}

然后您可以简化containerClass实现:

// Container Class
class containerClass {
    childClass child;
    static void clickHandler(string property, containerClass *data);
}

containerClass::containerClass() {
    // Set the event handler
    child.setClickHandler_External(&containerClass::clickHandler, this);
}

void containerClass::clickHandler(string property, containerClass *data) {
    //FINALLY, DO THE JOB WITH PROPERTY!!!
}

虽然很好地清理了实现,但是从所有容器实现者中删除了显式的转换,但这并非如此。关键是要防止你将错误的指针传递给setClickHandler_External,在调度事件时导致后端发生崩溃。

我的下一步将从实施中进一步了解,但需要更多有关您实际行动的细节。根据您的需求进行调查:

  • 继承:containerClass应该从childClass派生吗?这将提供对我们可以覆盖的虚拟功能表的访问。
  • Functors:查看boost :: function和boost :: bind来实现仿函数,消除中间静态函数调用。
  • Lambda函数:前沿(C ++ 11或更高版本),但可能非常适合这种转发功能。