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

时间:2018-08-18 23:13:59

标签: c++ gtk pass-by-reference gtk3 gtkmm

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

进行编译

当前功能:

  

显示带有简单SpinButton

的窗口

我想做什么:

  

将对spinbutton的引用传递给信号处理程序on_spinbutton_change,以便我可以getAdjustment并设置格式(如here

问题:

  

如何传递对spinbutton的引用以及其他可选数据(如简单的整数)?

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(不编译,尝试传递引用):

#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);
}

1 个答案:

答案 0 :(得分:1)

我必须承认几年前我从gtkmm切换到Qt。出于好奇,我在cygwin(我在Windows 10上)中安装了gtkmm 3,以准备示例(并了解我对gtkmm的看法有多生锈)。

考虑到OP的尝试,我使用了多个不同的签名,可以用来实现相同的结果。

  1. static gboolean Window::on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn);
    相应的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);
    相应的connect()

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

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

完整的示例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);
}

经过编译和测试:

$ 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

Snapshot of testGtkSpinBtnSig


请记住,OP实际上想修改GtkSpinButton文本的格式,这是另一个想法。

gtkmm绑定的一个显着扩展(与GTK +相比)是所有GTK +小部件类信号均作为虚拟方法提供的事实。 (我在Qt中非常想念此功能,在Qt中您有 个虚拟方法信号,但是(IMHO)从来没有两个信号。)实际上,这意味着,在gtkmm中,您总是有选择

  • 使派生的widget类具有增强的功能(为某些信号重载虚拟方法)或
  • (通过连接信号处理程序)修改单个实例的行为。

当然,除此之外,还可以派生一个小部件类,该小部件类将自己的方法连接到从基类继承的信号。 (在gtkmm 2.4中,在极少数情况下,GTK +信号缺少虚拟方法时,我必须这样做。)

因此,我修改了上面的示例,添加了派生的SpinButton并更改了信号回调以格式化旋转按钮文本。

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);
}

经过编译和测试:

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

Snapshot of testGtkSpinBtnSig (2nd version)