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

Handling events raised from a lower level object

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

我有一个容器 class,比如 containerClass 和一个 child class,比如 childClasschildClass object child 包含在 containerClass object container 中。

child object 是为了修改某物的属性而写的。为此,它有GtkEntryGtkButton等。当我单击 "save button" 时,会引发一个事件。

此事件必须由 container object 处理,因为 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!!!
}

这很好用并且可以完成工作。无论如何,我想知道是否有更聪明、更简洁的方法来实现相同的目标,也许不使用指向静态函数的指针,或者通过定义某种模式以便每次我需要具有相同的机制时重用。

提前致谢

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

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?这将提供对我们可以覆盖的虚函数 table 的访问。
  • 仿函数:查看 boost::function 和 boost::bind 来实现仿函数,消除中间静态函数调用。
  • Lambda 函数:前沿(C++11 或更高版本),但可能非常适合这种转发函数。

Gtkmm 使用 sigc++ 库为您处理所有这一切。不用自己写了

文档链接:

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

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

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