本章要实现的整体效果如下:
QEvent::Enter
鼠标进入事件,当鼠标进入到窗口/控件内部时,触发该事件,它对应的子类是 QEnterEvent
QEvent::Leave
鼠标离开事件,当鼠标进入到窗口/控件内部时,触发该事件
本节通过鼠标进入和离开一个标签,来演示这这两个事件
自定义一个标签控件 LabelX
,让它继承自 QLabel
,然后重写父类的 enterEvent
和 leaveEvent
。
首先,在左侧项目文件名上右键,然后选择 “添加新文件”,选择 “C++ Class”,如下:
新建类文件信息如下:
然后,把父类修改为 QLabel
来到 labelx.h
将父类由 QWidget
修改为 QLabel
,如下:
#include
class LabelX : public QLabel
{
//
};
来到 labelx.cpp 将父类由 QWidget 修改为 QLabel,如下:
#include "labelx.h"
LabelX::LabelX(QWidget* parent) : QLabel{parent}
{
}
首先,来到 labelx.h
,声明这两个函数:
class LabelX : public QLabel
{
protected:
// 鼠标进入/离开事件
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
};
然后,来到 labelx.cpp
实现这两个函数:
static int cnt = 1;
void LabelX::enterEvent(QEvent* event)
{
Q_UNUSED(event)
// 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++));
}
可以通过 qDebug() 在控制台输出,不过为了更直观,直接显示到标签上;
定义了一个静态变量,实现对进入和离开的计数;
使用 Q_UNUSED 宏,可以消除 “unused parameter” 的警告;
来到 enter_leave_widget.cpp
,在构造函数中添加 LabelX
控件,如下:
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(0, 0, 0, 0);
// 1. 添加一个自定义的标签 LabelX
LabelX* lblX = new LabelX(this);
lblX->setText("");
lblX->setFrameShape(QFrame::Box);
lblX->setFixedHeight(50);
lblX->setAlignment(Qt::AlignCenter);
lblX->setStyleSheet("background-color: red;color: white;font-size: 25px");
verticalLayout->addWidget(lblX);
}
此时运行程序,每当鼠标进入和离开标签时,计数都会加1,如下:
给一个目标对象,安装一个事件过滤器对象,语法如下:
monitoredObj->installEventFilter(filterObj);
这样:
所有发向 monitoredObj
的事件,都会被 filterObj
截获/过滤
截获/过滤的位置是 filterObj
的 eventFilter()
函数中
eventFilter()
函数返回一个 bool 类型, 返回 true
表示事件被截获,不再发送给 monitoredObj
,返回 false
表示事件会接着传递给 monitoredObj
接下来,通过一个案例来演示事件过滤器的使用:
首先,在 enter_leave_widget.h
文件中添加一个 QLabel
的成员变量,如下:
#include
class EnterLeaveWidget : public QWidget
{
private:
QLabel* lbl;
};
然后,在 enter_leave_widget.cpp
的构造中,添加一个 QLabel
控件,如下:
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
// 2. 添加一个标准的QLabel
lbl = new QLabel(this);
lbl->setText("");
lbl->setFrameShape(QFrame::Box);
lbl->setFixedHeight(50);
lbl->setAlignment(Qt::AlignCenter);
lbl->setStyleSheet("background-color: blue;color: white;font-size: 25px");
verticalLayout->addWidget(lbl);
}
在 enter_leave_widget.cpp
的构造中,为 QLabel
控件安装事件过滤器,如下:
EnterLeaveWidget::EnterLeaveWidget(QWidget* parent) : QWidget{parent}
{
// ...
lbl->installEventFilter(this);
}
这里将 lbl
的事件过滤器指定为 this
,那么所有的发给 lbl
的事件都会被当前窗口截获。
重写当前窗口的 eventFilter()
函数
首先,在 enter_leave_widget.h
文件中声明该函数,如下:
class EnterLeaveWidget : public QWidget
{
protected:
bool eventFilter(QObject* watched, QEvent* event);
};
然后,在 enter_leave_widget.cpp
文件中实现该函数,如下:
#include
static int cnt = 1;
// 查看帮助文档, 拷贝
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)
,其他事件交由父类处理;
此时运行,在当前窗口就可以截获发向 QLabel
的进入和离开事件了,如下: