简体   繁体   English

通过引用传递给信号处理程序

[英]Passing by reference to signal handler

Compile with g++ main.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs)g++ main.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs)

What it currently does:它目前的作用:

Displays a window with a simple SpinButton显示一个带有简单SpinButton的窗口

What I want to do:我想做的事:

Pass in a reference of spinbutton to the signal handler on_spinbutton_change so that I can getAdjustment and set the formatting (like here )spinbutton的引用传递给信号处理程序on_spinbutton_change以便我可以getAdjustment并设置格式(如此

Question:题:

How do I pass in a reference of spinbutton and optionally additional data (like a simple integer)?如何传入spinbutton的引用和可选的附加数据(如简单的整数)?

main.cc (compiles fine, does not pass reference): main.cc(编译正常,不传递引用):

#include <iostream>
#include <gtkmm/application.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>

class HelloWorld : public Gtk::Window {
public:
    HelloWorld();
    virtual ~HelloWorld();

protected:
    static gboolean on_spinbutton_change();
    Gtk::SpinButton spinbutton;
};

HelloWorld::HelloWorld() {
    spinbutton.signal_output().connect(sigc::ptr_fun(&HelloWorld::on_spinbutton_change));
    add(spinbutton);
    spinbutton.show();
}

HelloWorld::~HelloWorld() {}

gboolean HelloWorld::on_spinbutton_change() {
    std::cout << "Hello World" << std::endl;
    return true;
}

int main (int argc, char *argv[]) {
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
    HelloWorld helloworld;
    return app->run(helloworld);
}

main.cc (does not compile, attempt to pass reference): main.cc(不编译,尝试传递引用):

#include <iostream>
#include <gtkmm/application.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>

class HelloWorld : public Gtk::Window {
public:
    HelloWorld();
    virtual ~HelloWorld();

protected:
    static gboolean on_spinbutton_change(Gtk::SpinButton *spin);
    Gtk::SpinButton spinbutton;
};

HelloWorld::HelloWorld() {
    spinbutton.signal_output().connect(sigc::bind<Gtk::SpinButton*>(sigc::ptr_fun(&HelloWorld::on_spinbutton_change), spinbutton));
    add(spinbutton);
    spinbutton.show();
}

HelloWorld::~HelloWorld() {}

gboolean HelloWorld::on_spinbutton_change(Gtk::SpinButton *spin) {
    std::cout << "Hello World" << std::endl;
    return true;
}

int main (int argc, char *argv[]) {
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
    HelloWorld helloworld;
    return app->run(helloworld);
}

I must admit that I switched from gtkmm to Qt some years ago.我必须承认,几年前我从 gtkmm 切换到 Qt。 Out of curiosity, I installed gtkmm 3 in my cygwin (I'm on Windows 10) to prepare a sample (and find out how rusty I've become concerning gtkmm).出于好奇,我在我的cygwin (我在 Windows 10 上)中安装了 gtkmm 3 来准备一个样本(并了解我对 gtkmm 的生疏程度)。

Considering the attempts of OP, I used multiple different signatures which can be used to achieve the same result.考虑到 OP 的尝试,我使用了多个不同的签名,可以用来实现相同的结果。

  1. static gboolean Window::on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn);
    the corresponding connect() :相应的connect()

     _gtkSpinBtn1.signal_output().connect( sigc::bind( sigc::ptr_fun(&Window::on_spinbtn_output_p), &_gtkSpinBtn1));
  2. static gboolean Window::on_spinbtn_output_r(Gtk::SpinButton &gtkSpinBtn);
    the corresponding connect() :相应的connect()

     _gtkSpinBtn2.signal_output().connect( sigc::bind( sigc::ptr_fun(&Window::on_spinbtn_output_r), sigc::ref(_gtkSpinBtn2)));
  3. gboolean Window::on_spinbtn3_output() (non-static) gboolean Window::on_spinbtn3_output() (非静态)
    the corresponding connect() :相应的connect()

     _gtkSpinBtn3.signal_output().connect( sigc::mem_fun(this, &Window::on_spinbtn3_output));

The complete sample testGtkSpinBtnSig.cc :完整的示例testGtkSpinBtnSig.cc

#include <iostream>
#include <gtkmm/application.h>
#include <gtkmm/box.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>

class Window: public Gtk::Window {

  private:
    Gtk::VBox _gtkVBox;
    Gtk::SpinButton _gtkSpinBtn1;
    Gtk::SpinButton _gtkSpinBtn2;
    Gtk::SpinButton _gtkSpinBtn3;

  public:
    Window();
    virtual ~Window() = default;
    Window(const Window&) = delete;
    Window& operator=(const Window&) = delete;

  protected:
    static gboolean on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn);
    static gboolean on_spinbtn_output_r(Gtk::SpinButton &gtkSpinBtn);
    gboolean on_spinbtn3_output();
};

Window::Window(): Gtk::Window()
{
  _gtkSpinBtn1.set_range(0.0, 10.0); _gtkSpinBtn1.set_value(1.0);
  _gtkVBox.pack_start(_gtkSpinBtn1);
  _gtkSpinBtn2.set_range(0.0, 10.0); _gtkSpinBtn2.set_value(2.0);
  _gtkVBox.pack_start(_gtkSpinBtn2);
  _gtkSpinBtn3.set_range(0.0, 10.0); _gtkSpinBtn3.set_value(3.0);
  _gtkVBox.pack_start(_gtkSpinBtn3);
  add(_gtkVBox);
  _gtkVBox.show_all();
  // install signal handlers
  _gtkSpinBtn1.signal_output().connect(
    sigc::bind(
      sigc::ptr_fun(&Window::on_spinbtn_output_p),
      &_gtkSpinBtn1));
  _gtkSpinBtn2.signal_output().connect(
    sigc::bind(
      sigc::ptr_fun(&Window::on_spinbtn_output_r),
      sigc::ref(_gtkSpinBtn2)));
  _gtkSpinBtn3.signal_output().connect(
    sigc::mem_fun(this, &Window::on_spinbtn3_output));
}

gboolean Window::on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn)
{
  std::cout << "Window::on_spinbtn_output_p(): pGtkSpinBtn->get_value(): "
    << pGtkSpinBtn->get_value() << '\n';
  return true;
}

gboolean Window::on_spinbtn_output_r(Gtk::SpinButton &gtkSpinBtn)
{
  std::cout << "Window::on_spinbtn_output_r(): gtkSpinBtn.get_value(): "
    << gtkSpinBtn.get_value() << '\n';
  return true;
}

gboolean Window::on_spinbtn3_output()
{
  std::cout << "Window::on_spinbtn_output(): _gtkSpinBtn3.get_value(): "
    << _gtkSpinBtn3.get_value() << '\n';
  return true;
}

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv, "Test SpinButton Signals");
  Window gtkWin;
  return app->run(gtkWin);
}

Compiled and tested:编译和测试:

$ g++ testGtkSpinBtnSig.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs) -o testGtkSpinBtnSig

$ ./testGtkSpinBtnSig
Window::on_spinbtn_output_p(): pGtkSpinBtn->get_value(): 1
Window::on_spinbtn_output_r(): gtkSpinBtn.get_value(): 2
Window::on_spinbtn_output(): _gtkSpinBtn3.get_value(): 3

testGtkSpinBtnSig 的快照


Remembering, that OP actually wants to modify the formatting of the GtkSpinButton text another idea came into mind.记住,OP 实际上想要修改GtkSpinButton文本的格式,这是另一个想法。

A notable extension of the gtkmm binding (in comparison to GTK+) is the fact that all the GTK+ widget class signals are provided as virtual methods. gtkmm 绑定的一个显着扩展(与 GTK+ 相比)是所有 GTK+ 小部件类信号都作为虚拟方法提供。 (I miss this feature very much in Qt where you have either virtual methods or signals but (IMHO) never both of them.) Practically, this means, in gtkmm you always have the option (我非常想念这个功能在Qt的,你要么虚方法信号,但(恕我直言)不会同时。)实际上,这意味着,在你的gtkmm随时选择

  • to make a derived widget class with enhanced capabilities (overloading the virtual methods for certain signals) or制作具有增强功能的派生小部件类(重载某些信号的虚拟方法)或
  • to modify the behavior of an individual instance (by connecting signal handlers).修改单个实例的行为(通过连接信号处理程序)。

Beside of this, it is, of course, also possible to derive a widget class which connects a method of its own to a signal inherited from the base class.除此之外,当然,也可以派生一个小部件类,该类将自己的方法连接到从基类继承的信号。 (In gtkmm 2.4, I had to do this in the rare cases where the virtual methods were missing for GTK+ signals.) (在 gtkmm 2.4 中,我不得不在极少数情况下这样做,即 GTK+ 信号缺少虚拟方法。)

So, I modified the above sample adding a derived SpinButton and changing the signal callbacks to format the spin button text.因此,我修改了上面的示例,添加了一个派生的SpinButton并更改了信号回调以设置SpinButton文本的格式。

testGtkSpinBtnSig.cc : testGtkSpinBtnSig.cc :

#include <sstream>
#include <iomanip>
#include <gtkmm/application.h>
#include <gtkmm/box.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>

std::string format(double value)
{
  std::ostringstream out;
  out << std::fixed << std::setw(4) << std::setprecision(1) << std::setfill('0')
    << value;
  return out.str();
}

class SpinButton: public Gtk::SpinButton {
  public:
    SpinButton (double climb_rate = 0.0, guint digits = 0):
      Gtk::SpinButton(climb_rate, digits)
    { }
    virtual ~SpinButton() = default;
    SpinButton(const SpinButton&) = delete;
    SpinButton& operator=(const SpinButton&) = delete;

  protected:
    virtual bool on_output() override;
};

bool SpinButton::on_output()
{
  const double value = get_value();
  set_text(format(value));
  return true;
}

class Window: public Gtk::Window {

  private:
    Gtk::VBox _gtkVBox;
    Gtk::SpinButton _gtkSpinBtn1;
    Gtk::SpinButton _gtkSpinBtn2;
    Gtk::SpinButton _gtkSpinBtn3;
    SpinButton _gtkSpinBtn4; // derived SpinButton

  public:
    Window();
    virtual ~Window() = default;
    Window(const Window&) = delete;
    Window& operator=(const Window&) = delete;

  protected:
    static gboolean on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn);
    static gboolean on_spinbtn_output_r(Gtk::SpinButton &gtkSpinBtn);
    gboolean on_spinbtn3_output();
};

Window::Window(): Gtk::Window()
{
  _gtkSpinBtn1.set_range(0.0, 10.0); _gtkSpinBtn1.set_value(1.0);
  _gtkVBox.pack_start(_gtkSpinBtn1);
  _gtkSpinBtn2.set_range(0.0, 10.0); _gtkSpinBtn2.set_value(2.0);
  _gtkVBox.pack_start(_gtkSpinBtn2);
  _gtkSpinBtn3.set_range(0.0, 10.0); _gtkSpinBtn3.set_value(3.0);
  _gtkVBox.pack_start(_gtkSpinBtn3);
  _gtkSpinBtn4.set_range(0.0, 10.0); _gtkSpinBtn4.set_value(4.0);
  _gtkVBox.pack_start(_gtkSpinBtn4);
  add(_gtkVBox);
  _gtkVBox.show_all();
  // install signal handlers
  _gtkSpinBtn1.signal_output().connect(
    sigc::bind(
      sigc::ptr_fun(&Window::on_spinbtn_output_p),
      &_gtkSpinBtn1));
  _gtkSpinBtn2.signal_output().connect(
    sigc::bind(
      sigc::ptr_fun(&Window::on_spinbtn_output_r),
      sigc::ref(_gtkSpinBtn2)));
  _gtkSpinBtn3.signal_output().connect(
    sigc::mem_fun(this, &Window::on_spinbtn3_output));
}

gboolean Window::on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn)
{
  pGtkSpinBtn->set_text(format(pGtkSpinBtn->get_value()));
  return true;
}

gboolean Window::on_spinbtn_output_r(Gtk::SpinButton &gtkSpinBtn)
{
  gtkSpinBtn.set_text(format(gtkSpinBtn.get_value()));
  return true;
}

gboolean Window::on_spinbtn3_output()
{
  _gtkSpinBtn3.set_text(format(_gtkSpinBtn3.get_value()));
  return true;
}

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv, "Test SpinButton Signals");
  Window gtkWin;
  return app->run(gtkWin);
}

Compiled and tested:编译和测试:

$ g++ testGtkSpinBtnSig.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs) -o testGtkSpinBtnSig

testGtkSpinBtnSig 快照(第二版)

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

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