通过引用传递给信号处理程序
Passing by reference to signal handler
用g++ main.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs)
编译
目前的工作:
Displays a window with a simple SpinButton
我想做的事情:
Pass in a reference of spinbutton
to the signal handler on_spinbutton_change
so that I can getAdjustment
and set the formatting (like here)
问题:
How do I pass in a reference of spinbutton
and optionally additional data (like a simple integer)?
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);
}
我必须承认,几年前我从 gtkmm 转向了 Qt。出于好奇,我在我的 cygwin(我在 Windows 10)中安装了 gtkmm 3 来准备一个示例(并找出我对 gtkmm 的生疏程度)。
考虑到OP的尝试,我使用了多个不同的签名可以达到同样的效果
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));
static gboolean Window::on_spinbtn_output_r(Gtk::SpinButton >kSpinBtn);
对应的connect()
:
_gtkSpinBtn2.signal_output().connect(
sigc::bind(
sigc::ptr_fun(&Window::on_spinbtn_output_r),
sigc::ref(_gtkSpinBtn2)));
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 >kSpinBtn);
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 >kSpinBtn)
{
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
请记住,OP 实际上想要修改 GtkSpinButton
文本的格式,我想到了另一个想法。
gtkmm 绑定的一个显着扩展(与 GTK+ 相比)是所有 GTK+ 小部件 class 信号都是作为虚拟方法提供的。 (我非常想念 Qt 中的这个功能,你有 either 虚拟方法 或 信号,但(恕我直言)从来没有。)实际上,这意思是,在 gtkmm 中你总是有选项
- 制作具有增强功能的派生小部件class(为某些信号重载虚拟方法)或
- 修改单个实例的行为(通过连接信号处理程序)。
除此之外,当然也可以派生一个小部件 class,它将自己的方法连接到从基础 class 继承的信号。 (在 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 >kSpinBtn);
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 >kSpinBtn)
{
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
用g++ main.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs)
目前的工作:
Displays a window with a simple
SpinButton
我想做的事情:
Pass in a reference of
spinbutton
to the signal handleron_spinbutton_change
so that I cangetAdjustment
and set the formatting (like here)
问题:
How do I pass in a reference of
spinbutton
and optionally additional data (like a simple integer)?
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);
}
我必须承认,几年前我从 gtkmm 转向了 Qt。出于好奇,我在我的 cygwin(我在 Windows 10)中安装了 gtkmm 3 来准备一个示例(并找出我对 gtkmm 的生疏程度)。
考虑到OP的尝试,我使用了多个不同的签名可以达到同样的效果
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));
static gboolean Window::on_spinbtn_output_r(Gtk::SpinButton >kSpinBtn);
对应的connect()
:_gtkSpinBtn2.signal_output().connect( sigc::bind( sigc::ptr_fun(&Window::on_spinbtn_output_r), sigc::ref(_gtkSpinBtn2)));
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 >kSpinBtn);
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 >kSpinBtn)
{
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
请记住,OP 实际上想要修改 GtkSpinButton
文本的格式,我想到了另一个想法。
gtkmm 绑定的一个显着扩展(与 GTK+ 相比)是所有 GTK+ 小部件 class 信号都是作为虚拟方法提供的。 (我非常想念 Qt 中的这个功能,你有 either 虚拟方法 或 信号,但(恕我直言)从来没有。)实际上,这意思是,在 gtkmm 中你总是有选项
- 制作具有增强功能的派生小部件class(为某些信号重载虚拟方法)或
- 修改单个实例的行为(通过连接信号处理程序)。
除此之外,当然也可以派生一个小部件 class,它将自己的方法连接到从基础 class 继承的信号。 (在 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 >kSpinBtn);
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 >kSpinBtn)
{
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