Question

I'm just learning Qt with C++. I have successfully implemented signals and slots to trap standard events like ButtonPushed(), etc. However, I want to have a function called when I mouse over and mouse out of a QLabel. It looks like QHoverEvent will do what I need, but I can't seem to find any tutorials or examples on how to implement this. Is it done the same way as signals and slots?. I tried:

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

.. but the function didn't get called when I hovered over the label.

Here is the function, listed in the header file as a public slot:

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

Can anyone help me figure this out or point me to a good example?

EDIT:

After reading a post below, I found no setFlag() member to call for my label widget, but I did try:

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

And updated TestFunc() accordingly. But still nothing happens when I mouse over.

After looking I am not sure QLabel even inherits the mouseMoveEvent() even from QWidget. If this is true, is there a widget that does, or a list of objects that inherit it somewhere?. All I can tell from the documentation on their site is how many inherited functions an object has..

Was it helpful?

Solution

Using signals and slots for this purpose isn't going to work.

mouseMoveEvent() is not a signal or meta-method and cannot be connected to a slot.

Subclassing the widget class and overriding mouseMoveEvent() will allow you to get mouse-move-events, but that is a very heavyweight way to accomplish this (and adds one more class to your source base).

Instead, consider implementing an eventFilter() method on your MyDialog class and installing it on the QLabel. With this event filter method, you can intercept all the events for a given QObject instance.

Here is the documentation on Event Filters.

http://doc.qt.io/qt-4.8/eventsandfilters.html#event-filters

Additionally, through looking at the code sample, I'd recommend you take a moment to investigate what the SIGNAL() and SLOT() macros do. You can see how they are defined in $QTDIR/src/corelib/kernel/qobjectdefs.h

OTHER TIPS

According to the document link you give you're only going to get this QHoverEvent if your widget has the Qt::WA_Hover flag.

After constructing the widget call:

widget->setAttribute(Qt::WA_Hover);

and see if it works.

Another way of achieving the same result is to override mouseMoveEvent() in your widget
notice that this function too will not be normally called unless you call:

widget->setMouseTracking(true);

This is basically how QT implements the hover event internally.

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

Forces Qt to generate paint events when the mouse enters or leaves the widget. This feature is typically used when implementing custom styles; see the Styles example for details.

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

This QStyle::polish() overload is called once on every widget drawn using the style. We reimplement it to set the Qt::WA_Hover attribute on QPushButtons and QComboBoxes. When this attribute is set, Qt generates paint events when the mouse pointer enters or leaves the widget. This makes it possible to render push buttons and comboboxes differently when the mouse pointer is over them.

How to receive Enter and Leave Events on a QWidget

  1. Set the Widget Attribute for WA_Hover

    // in your widget's constructor (probably)
    this->setAttribute(Qt::WA_HOVER, true);
    
  2. Implement QWidget::enterEvent() and 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);
    }
    
  3. Done

QHoverEvent in QWidget

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

UPDATE:

Simple Example

Hover the button and see the count change. Look at the application output for more information.

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

Hope that helps.

I was having the same issue, I came to the following solution design:

In my main widget, I'd like to process hover events of some selected objects. For this reason, I created 2 slots on my MainWindow:

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

Then I created an Event Filter class like this:

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

You can see this class will fire either HoverIn or HoverOut depending on what happened. This approach does not need settings of Qt::WA_Hover

Now as last step, we need to instruct which elements are to be filtered and connect signals and slots. I will create a private pointer to event filter in mainwindow.h

class MainWindow : public QWidget
{
    Q_OBJECT

...

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

private:

    HoverEventFilter* hoverEventFilter;

...

};

And in constructor, I add this:

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*)));

Now whenever I wish to receive hover events on some object, I just set event filter on it, like this:

this->ui->someLabelOrWhatever->installEventFilter(this->hoverEventFilter);

What is left is implementation of onHoverIn and onHoverOut in MainWindow. They both share the same idea so I will show just onHoverIn

void MainWindow::onHoverIn(QObject *object)
{
    QString objectName = object->objectName();

    switch(objectName){
        // do something depending on name of the widget
    }
}

You can extend this so easily, to process hover events on new item, you just set an event listener on it and take care of what you wish to do in the onHoverIn and onHoverOut methods. No need to subclass any widgets.

QHoverEvent is only for hover widgets, you want to implement the enterEvent and leaveEvent handlers by subclassing the widget instead. If you want to use an event filter instead, the corresponding event types are QEvent::Enter and QEvent::Leave.

If you simply need to change the appearance of the widget, you might want to look into Qt stylesheets, as they provide a :hover selector.

You need to subclass or filter focusInEvent and focusOutEvent of that particular widget.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top