如何在Qt中实现QHoverEvent?

9

我正在学习使用C++的Qt框架。我已经成功地实现了信号和槽来捕获标准事件,例如ButtonPushed()等。但是,我想在鼠标悬停和移出QLabel时调用一个函数。看起来QHoverEvent可以满足我的需求,但我似乎找不到任何关于如何实现它的教程或示例。它是否与信号和槽的实现方式相同?我尝试了:

connect(ui.lbl_test, SIGNAL(QHoverEvent), this, SLOT(TestFunc(QEvent::Type type, const QPoint & pos, const QPoint & oldPos)));

但是当我悬停在标签上时,该函数没有被调用。

这是一个函数,在头文件中列为公共槽:

void MyDialog::TestFunc(QEvent::Type type, const QPoint & pos, const QPoint & oldPos) {
     QMessageBox::information(this, tr("Hey"), tr("Listen!"));
}

有人能帮我弄清楚这个问题或者给我一个好的例子吗?

编辑:

在阅读下面的帖子后,我发现我的标签小部件没有setFlag()成员可调用,但我尝试了:

    ui.lbl_test->setMouseTracking(true);
    connect(ui.lbl_test, SIGNAL(ui.lbl_test->mouseMoveEvent()), this, SLOT(TestFunc(QMouseEvent *event)));

我已经相应地更新了TestFunc(),但鼠标悬停时仍然没有反应。

看完代码,我不确定QLabel是否从QWidget继承了mouseMoveEvent()。如果是这样的话,有没有一个小部件是从QWidget继承的呢?或者有没有一份清单列出了哪些对象是继承自它的呢?从他们网站上的文档中我只能看到一个对象有多少个继承函数。

6个回答

17

http://qt-project.org/doc/qt-5/qwidget.html#enterEvent

http://qt-project.org/doc/qt-5/qwidget.html#leaveEvent

http://qt-project.org/doc/qt-5/qt.html#widget-attributes

Qt::WA_Hover

当鼠标进入或离开窗口小部件时,强制Qt生成绘图事件。该功能通常用于实现自定义样式;有关详细信息,请参见Styles示例。

http://qt-project.org/doc/qt-5/qtwidgets-widgets-styles-example.html#norwegianwoodstyle-class-implementation

此QStyle :: polish()重载在使用该样式绘制的每个小部件上调用一次。我们重新实现它,以在QPushButtons和QComboBoxes上设置Qt :: WA_Hover属性。设置此属性后,当鼠标指针进入或离开窗口小部件时,Qt会生成绘画事件。这使得在鼠标指针悬停在其上时,可以以不同的方式呈现推按钮和组合框。

如何在QWidget上接收进入和离开事件

  1. 设置WA_Hover小部件属性

// in your widget's constructor (probably)
this->setAttribute(Qt::WA_HOVER, true);
  • 实现 QWidget::enterEvent()QWidget::leaveEvent()

  • void Widget::enterEvent(QEvent * event)
    {
        qDebug() << Q_FUNC_INFO << this->objectName();
        QWidget::enterEvent(event);
    }
    
    void Widget::leaveEvent(QEvent * event)
    {
        qDebug() << Q_FUNC_INFO << this->objectName();
        QWidget::leaveEvent(event);
    }
    
  • 完成

  • QWidget中的QHoverEvent

    http://qt-project.org/doc/qt-5/qhoverevent.html#details

    http://qt-project.org/doc/qt-5/qobject.html#event

    http://qt-project.org/doc/qt-5/qwidget.html#event

    // in your widget's constructor (probably)
    this->setAttribute(Qt::WA_HOVER, true);
    // ...
    
    void Widget::hoverEnter(QHoverEvent * event) {qDebug() << Q_FUNC_INFO << this->objectName();}
    void Widget::hoverLeave(QHoverEvent * event) {qDebug() << Q_FUNC_INFO << this->objectName();}
    void Widget::hoverMove(QHoverEvent * event) {qDebug() << Q_FUNC_INFO << this->objectName();}
    
    bool Widget::event(QEvent * e)
    {
        switch(e->type())
        {
        case QEvent::HoverEnter:
            hoverEnter(static_cast<QHoverEvent*>(e));
            return true;
            break;
        case QEvent::HoverLeave:
            hoverLeave(static_cast<QHoverEvent*>(e));
            return true;
            break;
        case QEvent::HoverMove:
            hoverMove(static_cast<QHoverEvent*>(e));
            return true;
            break;
        default:
            break;
        }
        return QWidget::event(e);
    }
    

    更新:

    简单示例

    将鼠标悬停在按钮上,查看计数器的变化。更多信息请查看应用程序输出。

    https://gist.github.com/peteristhegreat/d6564cd0992351f98aa94f869be36f77

    希望对你有所帮助。


    this->setAttribute(Qt::WA_HOVER, true); // Qt: - Mahmoud Badri
    扩展到Python时,可能不需要使用setAttribute。我扩展了一个QLabel,并且没有需要调用setAttribute。 - PfunnyGuy
    请注意,QWidget::enterEvent()QWidget::leaveEvent()不是虚函数。 - juzzlin

    14

    根据您提供的文档链接,只有在您的小部件设置了Qt::WA_Hover标志时,才会收到此事件。

    构建小部件后,请调用:

    widget->setAttribute(Qt::WA_Hover);
    

    并查看它是否有效。

    另一种实现相同结果的方法是在您的小部件中覆盖mouseMoveEvent(),请注意,除非您调用:

    widget->setMouseTracking(true);
    

    这基本上是QT内部实现悬停事件的方式。


    2
    嗯,看起来你想说的是 widget->setAttribute(Qt::WA_Hover);。 - Alpants

    7
    使用信号和槽来实现这个目的是行不通的。 mouseMoveEvent() 不是一个信号或元方法,不能连接到一个槽上。
    子类化窗口小部件类并覆盖 mouseMoveEvent() 将允许您获取鼠标移动事件,但这是一种非常笨重的方法(并且会在源代码中添加一个类)。
    相反,考虑在您的 MyDialog 类上实现一个 eventFilter() 方法,并将其安装在 QLabel 上。使用这个事件过滤器方法,您可以拦截给定 QObject 实例的所有事件。
    这里是事件过滤器的文档。 http://doc.qt.io/qt-4.8/eventsandfilters.html#event-filters 此外,通过查看代码示例,我建议您花点时间了解 SIGNAL()SLOT() 宏的作用。您可以看到它们在 $QTDIR/src/corelib/kernel/qobjectdefs.h 中是如何定义的。

    3

    我发现有同样的问题,于是设计了以下解决方案:

    在我的主窗口小部件中,我希望处理一些选定对象的悬停事件。因此,我在MainWindow上创建了2个插槽:

    public slots:
        void onHoverIn(QObject* object);
        void onHoverOut(QObject* object);
    

    接下来我创建了一个类似于以下的事件过滤器类:

    hovereventfilter.h

    #ifndef HOVEREVENTFILTER_H
    #define HOVEREVENTFILTER_H
    
    #include <QObject>
    #include <QEvent>
    
    class HoverEventFilter : public QObject
    {
        Q_OBJECT
    public:
        explicit HoverEventFilter(QObject *parent = 0);
    
    signals:
        void HoverIn(QObject *);
        void HoverOut(QObject *);
    
    public slots:
    
    protected:
        bool eventFilter(QObject *watched, QEvent *event);
    };
    
    #endif // HOVEREVENTFILTER_H
    

    hovereventfilter.cpp

    #include "hovereventfilter.h"
    
    HoverEventFilter::HoverEventFilter(QObject *parent) : QObject(parent)
    {
    
    }
    
    bool HoverEventFilter::eventFilter(QObject *watched, QEvent *event)
    {
    
        QEvent::Type t = event->type();
    
        switch(t){
        case QEvent::Enter:
            emit HoverIn(watched);
            break;
    
        case QEvent::Leave:
            emit HoverOut(watched);
            break;
        default:
            return false;
        }
    
        return true;
    }
    

    你可以看到,这个类会根据发生的情况触发HoverIn或HoverOut。这种方法不需要设置Qt :: WA_Hover。
    现在作为最后一步,我们需要指示要过滤哪些元素并连接信号和插槽。我将在mainwindow.h中创建一个私有指针来过滤事件。
    class MainWindow : public QWidget
    {
        Q_OBJECT
    
    ...
    
    public slots:
        void onHoverIn(QObject* object);
        void onHoverOut(QObject* object);
    
    private:
    
        HoverEventFilter* hoverEventFilter;
    
    ...
    
    };
    

    在构造函数中,我添加了以下内容:
    this->hoverEventFilter = new HoverEventFilter(this);
    
    connect(this->hoverEventFilter, SIGNAL(HoverIn(QObject*)), this, SLOT(onHoverIn(QObject*)));
    connect(this->hoverEventFilter, SIGNAL(HoverOut(QObject*)), this, SLOT(onHoverOut(QObject*)));
    

    现在,每当我希望在某个对象上接收鼠标悬停事件时,我只需在其上设置事件过滤器,如下所示:
    this->ui->someLabelOrWhatever->installEventFilter(this->hoverEventFilter);
    

    剩下的是在MainWindow中实现onHoverInonHoverOut。它们都共享相同的思路,因此我只会展示onHoverIn
    void MainWindow::onHoverIn(QObject *object)
    {
        QString objectName = object->objectName();
    
        switch(objectName){
            // do something depending on name of the widget
        }
    }
    

    您可以轻松地扩展它,以处理新项目上的悬停事件,只需在其上设置事件监听器,并在onHoverInonHoverOut方法中处理您希望执行的操作即可。无需子类化任何小部件。


    1

    QHoverEvent仅适用于悬停小部件,如果您想通过子类化小部件来实现enterEventleaveEvent处理程序,则需要这样做。 如果您想使用事件过滤器,则相应的事件类型为QEvent::EnterQEvent::Leave

    如果您只需要更改小部件的外观,则可以尝试查看Qt样式表,因为它们提供了一个:hover选择器。


    -4

    1
    也许你的意思是hoverEnter和hoverLeave? - Anti Earth

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接