从另一个小部件触发检查按钮悬停事件

Posted

技术标签:

【中文标题】从另一个小部件触发检查按钮悬停事件【英文标题】:Trigger checkbutton hover event from another widget 【发布时间】:2021-05-28 09:13:24 【问题描述】:

我使用不带标签的Gtk::CheckButtonGtk::EventBox 内部的Gtk::Label 制作了一个自定义的从右到左检查按钮小部件。

我之所以这样做而不是简单地调用set_direction(Gtk::TEXT_DIR_RTL),是因为我想手动指定这些小部件的对齐方式。

我已经弄清楚点击标签时激活/停用检查按钮的状态,但我无法触发从标签到检查按钮的悬停事件。默认的Gtk::CheckButton 行为会触发可点击方形按钮上的悬停效果,以指示它在文本也悬停时被激活。如何在我的自定义从右到左检查按钮小部件上实现相同的行为?

以下是用于测试的最小可重现代码:

#include <gtkmm.h>

using Gtk::Application;
using Gtk::Button;
using Gtk::CheckButton;
using Gtk::EventBox;
using Gtk::Grid;
using Gtk::Label;
using Gtk::Window;

class MyWindow : public Window 
    Button      button;
    CheckButton checkbutton;
    EventBox    eventbox;
    Grid        grid;
    Label       label;

    bool on_label_clicked(GdkEventButton *);
    void arrange_content_layout();
    
public:
    MyWindow();
;

bool MyWindow::on_label_clicked(GdkEventButton *event)

    if (event->button == 1 && event->type == GDK_BUTTON_PRESS) 
        checkbutton.set_active(!checkbutton.get_active());
        return true;
    

    return false;


void MyWindow::arrange_content_layout()

    checkbutton.set_margin_start(6);
    
    button.set_margin_top(24);
    grid.child_property_width(button) = 2;
    
    grid.set_margin_top(24);
    grid.set_margin_start(24);
    grid.set_margin_end(24);
    grid.set_margin_bottom(24);


MyWindow::MyWindow()
    : button("Click to steal focus")
    , label ("Our custom RTL label")

    eventbox.add(label);
    eventbox.signal_button_press_event().connect(sigc::mem_fun(
            *this, &MyWindow::on_label_clicked));
    
    grid.add(eventbox);
    grid.add(checkbutton);
    grid.attach(button, 0, 1);
    
    add(grid);
    
    arrange_content_layout();
    set_default_size(120, 60);
    
    show_all();


int main()

    auto app = Application::create("domain.reverse.sample.rtl-checkbutton");
    
    MyWindow window;
    
    return app->run(window);

【问题讨论】:

您要手动指定什么对齐方式?使用 CSS 可能会更好。我认为不建议 GtkWidget:margin*,类似的 GtkContainer:border-width 在 GTK4 中被彻底删除(GtkContainer 也是如此,但仍然......) 居中 将Gtk::CheckButton 与一列中的其他切换按钮对齐,并将标签与另一列中的其余小部件对齐。这样,所有切换按钮都会在一列中对齐,之前的列也是如此。带有指定标签的默认Gtk::CheckButton 看起来彼此太近了,我不喜欢用空格使它们与周围的小部件对齐。 @underscore_d set_valignset_halign 【参考方案1】:

一种方法是使用set_state_flags() 并在标签悬停时欺骗从右到左复选按钮的视觉输出。

首先,您需要为eventbox启用这两个掩码来捕获enterleave事件:

Gdk::ENTER_NOTIFY_MASK Gdk::LEAVE_NOTIFY_MASK
eventbox.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);

并连接eventbox 信号

class MyWindow : public Window 
    ...
    bool on_label_entered(GdkEventCrossing *);
    bool on_label_exited(GdkEventCrossing *);
    ...


MyWindow::MyWindow()
    ...

    ...
    eventbox.signal_enter_notify_event().connect(sigc::mem_fun(
            *this, &MyWindow::on_label_entered));
    eventbox.signal_leave_notify_event().connect(sigc::mem_fun(
            *this, &MyWindow::on_label_exited));
    ...

最后,使用Gtk::STATE_FLAG_PRELIGHT 完成 UI 技巧

// Enter event
bool MyWindow::on_label_entered(GdkEventCrossing *event)

    if (event->mode != GDK_CROSSING_NORMAL) return false;

    checkbutton.set_state_flags(checkbutton.get_state_flags() | Gtk::STATE_FLAG_PRELIGHT);

    return true;


// Leave event
bool MyWindow::on_label_exited(GdkEventCrossing *event)

    if (event->mode != GDK_CROSSING_NORMAL) return false;

    checkbutton.unset_state_flags(Gtk::STATE_FLAG_PRELIGHT);

    return true;

【讨论】:

以上是关于从另一个小部件触发检查按钮悬停事件的主要内容,如果未能解决你的问题,请参考以下文章

如何在自定义元素或按钮小部件上触发事件?

从另一个文件中的按钮切换 QStackedWidget 中的小部件

如何从另一个小部件类更新小部件树 - Flutter

Kivy:从另一个类的小部件中检索文本?

dojo.dijit.Button 触发 onclick 事件两次

android小部件的按钮单击事件