I want to turn on Gtk::SpinButton
entry focus when mouse pointer enters this widget and then turn it off again when the pointer leaves.
The signal event doesn't seem to respond while the window is still running. But the std::cout
outputs are printed after I close the window.
How do I implement my expected widget behavior?
#include <gtkmm.h>
#include <iostream>
class SpinButtonExample : public Gtk::Window {
Gtk::Grid grid;
Gtk::Label label;
Glib::RefPtr<Gtk::Adjustment> adjustment;
Gtk::SpinButton spinbutton;
public:
SpinButtonExample();
bool on_enter_notify_event(GdkEventCrossing *);
bool on_leave_notify_event(GdkEventCrossing *);
};
SpinButtonExample::SpinButtonExample()
: label ("Hi")
, adjustment(Gtk::Adjustment::create(0, 0, 10))
, spinbutton(adjustment)
{
add_events(Gdk::ENTER_NOTIFY_MASK);
add_events(Gdk::LEAVE_NOTIFY_MASK);
spinbutton.signal_enter_notify_event().connect(
sigc::mem_fun(*this, &SpinButtonExample::on_enter_notify_event));
spinbutton.signal_leave_notify_event().connect(
sigc::mem_fun(*this, &SpinButtonExample::on_leave_notify_event));
grid.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
grid.set_column_homogeneous(true);
grid.set_margin_start(10);
grid.set_margin_end(10);
grid.set_margin_top(10);
grid.set_margin_bottom(10);
grid.add(label);
grid.add(spinbutton);
add(grid);
show_all();
}
bool
SpinButtonExample::on_enter_notify_event(GdkEventCrossing *event)
{
if (event->type == GDK_SCROLL) {
std::cout << "Mouse entered\n";
spinbutton.set_can_focus();
return true;
}
return false;
}
bool
SpinButtonExample::on_leave_notify_event(GdkEventCrossing *event)
{
if (event->type == GDK_LEAVE_NOTIFY) {
std::cout << "Mouse left\n";
spinbutton.set_can_focus(false);
return true;
}
return false;
}
int
main()
{
auto application = Gtk::Application::create("test.focus.spinbutton");
SpinButtonExample test;
return application->run(test);
}
Huge THANKS to underscore_d's comments above.
The answer to this is to direct our focus to another widget when mouse pointer leaves Gtk::SpinButton
widget and for enter event, grab the focus back.
Just turning on and off with set_can_focus()
won't work.
Below is the corrected solution:
#include <gtkmm.h>
#include <iostream>
class SpinButtonExample : public Gtk::Window {
Gtk::Grid grid;
Gtk::Label label;
Glib::RefPtr<Gtk::Adjustment> adjustment;
Gtk::SpinButton spinbutton;
Gtk::Button button;
public:
SpinButtonExample();
bool on_enter_notify_event(GdkEventCrossing *);
bool on_leave_notify_event(GdkEventCrossing *);
};
SpinButtonExample::SpinButtonExample()
: label ("Hi")
, adjustment(Gtk::Adjustment::create(0, 0, 10))
, spinbutton(adjustment)
, button ("Default")
{
add_events(Gdk::ENTER_NOTIFY_MASK);
add_events(Gdk::LEAVE_NOTIFY_MASK);
button.set_margin_start(10);
button.set_can_default();
button.grab_focus();
spinbutton.set_can_default(false);
spinbutton.signal_enter_notify_event().connect(
sigc::mem_fun(*this, &SpinButtonExample::on_enter_notify_event));
spinbutton.signal_leave_notify_event().connect(
sigc::mem_fun(*this, &SpinButtonExample::on_leave_notify_event));
grid.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
grid.set_column_homogeneous(true);
grid.set_margin_start(10);
grid.set_margin_end(10);
grid.set_margin_top(10);
grid.set_margin_bottom(10);
grid.add(label);
grid.add(spinbutton);
grid.add(button);
add(grid);
show_all();
}
bool
SpinButtonExample::on_enter_notify_event(GdkEventCrossing *event)
{
if (event->type == GDK_ENTER_NOTIFY) {
std::cout << "Mouse entered" << std::endl;
spinbutton.grab_focus();
return true;
}
return false;
}
bool
SpinButtonExample::on_leave_notify_event(GdkEventCrossing *event)
{
if (event->type == GDK_LEAVE_NOTIFY) {
std::cout << "Mouse left" << std::endl;
button.grab_focus();
return true;
}
return false;
}
int
main()
{
auto application = Gtk::Application::create("test.focus.spinbutton");
SpinButtonExample test;
return application->run(test);
}