连接到信号处理函数

gtkmm的部件类拥有信号访问器方法,例如:Gtk::Button::signal_clicked()。这些方法允许你将你的信号处理函数与信号相连接。gtkmm所使用的的libsigc++回调库提供了非常强的灵活性,它几乎允许你使用任何函数作为信号的处理程序,不过通常你会希望使用类的成员函数。在GTK的C代码中,这些信号处理程序被称为回调。

这是将信号处理函数与信号相连接的示例:

#include <gtkmm/button.h>

void on_button_clicked()
{
    std::cout << "Hello World" << std::endl;
}

int main()
{
    Gtk::Button button("Hello World");
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
}

在此代码(非功能性)中有很多事情要考虑,首先让我们确定代码的行为:

  • 信号处理函数是on_button_clicked()
  • 我们将其连接到一个名为buttonGtk::Button对象。
  • button发出clicked信号时,on_button_clicked()将被调用。

现在,我们再次看一下连接:

    ...
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
    ...

请注意,我们不会直接将一个指向on_button_clicked()的指针传递给信号的connect()方法。我们将调用sigc::ptr_fun()并将其返回值传递给connect()

sigc::ptr_fun()生成一个sigc::slot。槽对象看起来很像一个函数,但实际上是一个对象。这类对象也被称为函数对象或是函子。sigc::ptr_fun()为独立函数或静态成员函数生成槽。sigc::mem_fun()为特定实例的成员函数生成槽。

这是一个在动作中使用槽的较大示例:

void on_button_clicked();

class some_class
{
    void on_button_clicked();
};

some_class some_object;

int main()
{
    Gtk::Button button;
    button.signal_clicked().connect( sigc::ptr_fun(&on_button_clicked) );
    button.signal_clicked().connect( sigc::mem_fun(some_object, &some_class::on_button_clicked) );
}

第一个connect()调用与我们之前看到的没有什么区别。

接下来的一个调用更有趣些。使用两个参数调用sigc::mem_fun()。第一个参数是some_object,这是我们新的槽将指向的对象。第二个参数是指向其成员函数之一的指针。这个特定版本的sigc::mem_fun()将会创建一个槽,这个槽在被调用的时候将会调用指定对象上函数指针所指向的成员函数,在这个情况下调用的是some_object.on_button_clicked()

另一个与此示例有关的注意事项是,我们对同一个信号对象调用了两次connect()。所以当该按钮被点击时,这两个信号处理函数都将被调用。

你应该已经注意到了,按钮的clicked信号期望调用一个不接受任何参数的函数。事实上所有的信号都有这样的要求。所以你不能将一个接受两个参数的函数与期望所调用函数不接受参数的信号相关联,当然你可以通过使用sigc::bind()之类的适配器在一定程度上绕过这个限制。