繁体   English   中英

将gtk_signal_connect与c ++中的成员函数一起使用

[英]use gtk_signal_connect with a member function in c++

将GTK +信号连接到非静态成员函数的最佳方法是什么?

我有一个使用gtk的c ++ GUI类,我想做这样的事情:

Gui::Gui ()
{
  gtk_signal_connect(GTK_OBJECT(somObject),
                     "clicked",
                     GTK_SIGNAL_FUNC( &(this->ClickHandler) ),
                     NULL);
}

void Gui::ClickHandler(GtkWidget *w, gpointer data)
{
  // handle the click
}

我知道这不起作用b / c GTK _SIGNAL _FUNC不能指向成员函数,除非它是静态函数,那么最好的方法是什么? 有可能使用单个代理处理函数和boost :: bind吗? 这是我尝试过的:

gtk_signal_connect(GTK_OBJECT(somObject), "clicked", 
                   GTK_SIGNAL_FUNC( SigHandler ), 
                   boost::bind( &(Gui::ClickHandler), this) ); 

void SigHandler(GtkWidget *w, gpointer data) 
{
  data(w);
} 

void Gui::ClickHandler(GtkWidget *w) { // handle the click } 

这是错误:gui.cc:错误:'data'不能用作函数

我假设您的类包含信号处理程序需要访问的一些内部数据。 如果没有,只需使用静态函数作为信号处理程序。 否则,这里有几个想法:

  • 从成员函数中创建一个sigc ++或boost functor; 将其设置为传递给信号处理程序的数据。 使用只调用仿函数的通用信号处理程序。

  • 在构造期间,在某处注册类的每个实例,并使用信号处理程序为每个已注册的实例调用成员函数。

您将需要代理,但您可以执行一些模板魔术来帮助您生成代理。 像这样的东西:

template <class HandlerClass, class A1, void(HandlerClass::*HandlerFunc)(A1)>
struct GtkHandlerProxy {
  static void HandlerProxy(A1 a1, gpointer p) {
    (static_cast<HandlerClass*>(p)->*HandlerFunc)(a1);
  }
};

然后使用它:

Gui::Gui()
{
  gtk_signal_connect(
    GTK_OBJECT(somObject),
    "clicked",
    GTK_SIGNAL_FUNC(&GtkHandlerProxy<Gui, GtkWidget*, &Gui::ClickHandler>
      ::HandlerProxy),
    this);
}

你可能也想定义一个辅助宏:

#define GTK_SIGNAL_METHOD(Class, Handler, A1) \
   GTK_SIGNAL_FUNC(GtkHandlerProxy<Class, A1, &Class::Handler>::HandlerProxy)

这样你就可以写:

Gui::Gui()
{
  gtk_signal_connect(
    GTK_OBJECT(somObject),
    "clicked",
    GTK_SIGNAL_METHOD(GtkHandlerProxy, ClickHandler, GtkWidget*),
    this);
}

这仅涵盖单参数处理程序案例; 要处理像button_press_event这样的button_press_event ,你必须为2个以上的参数定义类似的帮助器。 Boost预处理器库可以帮助避免重复代码。

[编辑]

或者,您可以将函数对象本身作为p传递,它可能包含捕获的变量(例如boost::bindboost::lambda )。 这是看起来如何:

class Gui {
  ...

  // Member to ensure proper lifetime
  boost::function<void(GtkWidget*)> clickHandlerFunc;

  Gui() {
    ...
    clickHandlerFunc = boost::bind(&Gui::ClickHandler, this);
    gtk_signal_connect(
      GTK_OBJECT(somObject),
      "clicked",
      GTK_SIGNAL_FUNC(UniversalHandlerProxy<GtkWidget*>)
      &clickHandlerFunc);       
  }

  template <class A1>
  static void Gui::UniversalHandlerProxy(A1 a1, gpointer p) {
    (*static_cast< boost::function<void(A1)>* >(p))(a1);
  }

  void Gui::ClickHandler(GtkWidget* w, gpointer p) {
    ...     
  }
};

使用静态代理:

Gui::Gui ()
{
  gtk_signal_connect(GTK_OBJECT(somObject),
                     "clicked",
                     GTK_SIGNAL_FUNC(ClickHandlerProxy),
                     this);
}

void Gui::ClickHandler(GtkWidget *w)
{ /* handle the click */ }

void Gui::ClickHandlerProxy(GtkWidget *w, gpointer p)
{ static_cast<Gui*>(p)->ClickHandler(w); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM