How do I implement QHoverEvent in Qt?
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..
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.
This
QStyle::polish()
overload is called once on every widget drawn using the style. We reimplement it to set theQt::WA_Hover
attribute onQPushButtons
andQComboBoxes
. 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
Set the Widget Attribute for WA_Hover
// in your widget's constructor (probably) this->setAttribute(Qt::WA_HOVER, true);
Implement
QWidget::enterEvent()
andQWidget::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); }
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.