根据鼠标 enter/leave 事件打开和关闭小部件的焦点

Turn widget's focus on and off based on mouse enter/leave event

我想在鼠标指针进入此小部件时打开 Gtk::SpinButton 进入焦点,然后在鼠标指针离开时再次关闭它。

信号事件似乎没有响应,而 window 仍然是 运行。但是 std::cout 输出是在我关闭 window.

之后打印的

如何实现预期的小部件行为?

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

非常感谢 underscore_d 上面的评论。

答案是当鼠标指针离开 Gtk::SpinButton 小部件时将我们的焦点指向另一个小部件,对于进入事件,夺回焦点。

仅使用 set_can_focus() 打开和关闭是行不通的。

以下是更正的解决方案:

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