Compile with g++ main.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs)
What it currently does:
Displays a window with a simple
SpinButton
What I want to do:
Pass in a reference of
spinbutton
to the signal handleron_spinbutton_change
so that I cangetAdjustment
and set the formatting (like here)
Question:
How do I pass in a reference of
spinbutton
and optionally additional data (like a simple integer)?
main.cc (compiles fine, does not pass reference):
#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):
#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. 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).
Considering the attempts of OP, I used multiple different signatures which can be used to achieve the same result.
static gboolean Window::on_spinbtn_output_p(Gtk::SpinButton *pGtkSpinBtn);
the corresponding 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);
the corresponding connect()
:
_gtkSpinBtn2.signal_output().connect(
sigc::bind(
sigc::ptr_fun(&Window::on_spinbtn_output_r),
sigc::ref(_gtkSpinBtn2)));
gboolean Window::on_spinbtn3_output()
(non-static)
the corresponding connect()
:
_gtkSpinBtn3.signal_output().connect(
sigc::mem_fun(this, &Window::on_spinbtn3_output));
The complete sample 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);
}
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
Remembering, that OP actually wants to modify the formatting of the GtkSpinButton
text another idea came into mind.
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. (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
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.)
So, I modified the above sample adding a derived SpinButton
and changing the signal callbacks to format the spin button text.
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);
}
Compiled and tested:
$ g++ testGtkSpinBtnSig.cc -Wall $(pkg-config gtkmm-3.0 --cflags --libs) -o testGtkSpinBtnSig