本节通过鼠标进入和离开一个标签,来演示这这两个事件:
- 鼠标进入事件(
QEvent::Enter) - 鼠标离开事件(
QEvent::Leave)
当鼠标进入或者离开窗口/控件时,会被触发
本节实现效果,如下:
1. 通过自定义控件实现
自定义一个标签控件LabelX,让它继承自QLabel,然后重写父类的enterEvent()和leaveEvent()
首先,在左侧项目文件名上右键,选择 “Add New…”,选择 “C++ Class”,先继承自QWidget,如下:
然后,把父类由QWidget修改为QLabel,如下:
// labelx.h
#include <QLabel>
class LabelX : public QLabel {
Q_OBJECT
public:
explicit LabelX(QWidget *parent = nullptr);
signals:
};
// labelx.cpp
#include "labelx.h"
LabelX::LabelX(QWidget *parent) : QLabel{parent}
{
}
然后,来到LabelX类中,声明并实现enterEvent()、leaveEvent()两个函数,如下:
// labelx.h
class LabelX : public QLabel {
protected:
void enterEvent(QEnterEvent *event);
void leaveEvent(QEvent *event);
};
// labelx.cpp
static int cnt = 0; // 定义了一个静态变量,实现对进入和离开的计数;
void LabelX::enterEvent(QEnterEvent *event)
{
// 使用 Q_UNUSED 宏,可以消除 “unused parameter” 的警告
Q_UNUSED(event)
// 可以通过 qDebug() 在控制台输出,不过为了更直观,直接显示到标签上;
// qDebug() << "enterEvent: " << cnt++;
this->setText(QString("enterEvent: %1").arg(++cnt));
}
void LabelX::leaveEvent(QEvent *event)
{
Q_UNUSED(event)
// qDebug() << "leaveEvent: " << cnt++;
this->setText(QString("leaveEvent: %1").arg(cnt));
}
最后,不要忘记来到enter_leave_widget.cpp,在构造函数中将QLabel修改为LabelX,如下:
#include "labelx.h"
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(0, 0, 0, 0);
LabelX* lblx = new LabelX();
lblx->setFrameShape(QFrame::Box);
lblx->setFixedHeight(50);
lblx->setAlignment(Qt::AlignCenter);
lblx->setStyleSheet("background-color: blue; color: white; font-size: 25px");
verticalLayout->addWidget(lblx);
}
2. 通过事件过滤器实现
给一个被监控对象,安装一个事件过滤器对象,语法如下:
// 所有发向 monitoredObj 的事件,都会被 filterObj 对象的 eventFilter() 函数截获/过滤
// eventFilter() 函数返回一个 bool 类型:
// 1)返回 true 表示事件被截获,不再发送给 monitoredObj
// 2)返回 false 表示事件会接着传递给 monitoredObj
monitoredObj->installEventFilter(filterObj);
接下来,通过一个案例来演示事件过滤器的使用
首先,修改EnterLeaveWidget类中, 添加一个QLabel标签,如下:
// labelx.h
#include <QLabel>
class EnterLeaveWidget : public QWidget {
private:
QLabel* lbl;
};
// labelx.cpp
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
// ...
// 2. 添加一个标准的标签控件
lbl = new QLabel(this);
lbl->setFrameShape(QFrame::Box);
lbl->setFixedHeight(50);
lbl->setAlignment(Qt::AlignCenter);
lbl->setStyleSheet("background-color: red; color:white;font-size:25px");
verticalLayout->addWidget(lbl);
}
然后,在enter_leave_widget.cpp的构造中,为QLabel控件安装事件过滤器,如下:
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
// ...
// 这里将 lbl 的事件过滤器指定为 this,那么所有的发给 lbl 的事件都会被当前窗口截获。
lbl->installEventFilter(this);
}
最后,修改EnterLeaveWidget类,声明并实现eventFilter()函数,如下:
// enter_leave_widget.h
class EnterLeaveWidget : public QWidget
{
protected:
bool eventFilter(QObject* watched, QEvent* event);
};
// enter_leave_widget.cpp
#include <QEvent>
static int cnt = 0;
bool EnterLeaveWidget::eventFilter(QObject* watched, QEvent* event)
{
if (watched == lbl) {
if (event->type() == QEvent::Enter) {
lbl->setText(QString("enterEvent: %1").arg(++cnt));
} else if (event->type() == QEvent::Leave) {
lbl->setText(QString("leaveEvent: %1").arg(cnt));
}
}
return QWidget::eventFilter(watched, event);
}
说明:
- 这里判断下事件是否是发向
lbl的,然后再做处理,因为还有可能监控其他的控件; - 通过
QEvent类的type()函数,可以判断事件的类型; - 以上还通过一个静态变量,来对事件计数;
- 最后调用下父类的
QWidget::eventFilter(watched, event),其他事件交由父类处理;







