每个程序main ()函数的最后都会调用QApplication类的exec()函数,它会使应用程序进入事件循环,这样就可以使应用程序在运行时接收发生的各种事件。一旦有事件发生,Qt便会构建一个相应的QEvent子类的对象来表示它,然后将它传递给相应的QObject对象或者其子类对象。
举例一:
新建Qt Widget应用,项目名为myevent,基类选择QWidget,类名保持Widget不变。
第一步:
添加一个MyLineEdit类,头文件为mylineedit.h,源文件为mylineedit.cpp
mylineedit.h代码为:
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget * parent = nullptr);
protected:
void keyPressEvent(QKeyEvent *event) override;
};
#endif // MYLINEEDIT_H
mylineedit.cpp代码为:
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
MyLineEdit::MyLineEdit(QWidget *parent)
: QLineEdit(parent)
{
}
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "MyLineEdi键盘按下事件";
QLineEdit::keyPressEvent(event);
// event->ignore();
}
widget.h代码为:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class MyLineEdit;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget() override;
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
MyLineEdit *m_lineEdit;
};
#endif // WIDGET_H
widget.cpp代码为:
#include "widget.h"
#include "mylineedit.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_lineEdit = new MyLineEdit(this);
m_lineEdit->move(100, 100);
}
Widget::~Widget()
{
}
void Widget::keyPressEvent(QKeyEvent *event)
{
Q_UNUSED(event)
qDebug() << "Widget键盘按下事件";
}
运行结果为:
MyLineEdi键盘按下事件
改造一下:
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "MyLineEdi键盘按下事件";
QLineEdit::keyPressEvent(event);
event->ignore();
}
在MyLineEdit中添加了event->ignore();
再运行:
这时候看到MyLineEdit的父窗口也响应了这个按键事件。
事件的传递
举例二
widget.h代码:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class MyLineEdit;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget() override;
protected:
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
private:
MyLineEdit *m_lineEdit;
};
#endif // WIDGET_H
widget.cpp代码:
#include "widget.h"
#include "mylineedit.h"
#include <QEvent>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_lineEdit = new MyLineEdit(this);
m_lineEdit->move(100, 100);
m_lineEdit->installEventFilter(this);
}
Widget::~Widget()
{
}
bool Widget::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "Widget的event()函数";
}
return QWidget::event(event);
}
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
if (obj == m_lineEdit)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "Widget的事件过滤器";
// return true;
}
}
return QWidget::eventFilter(obj, event);
}
void Widget::keyPressEvent(QKeyEvent *event)
{
Q_UNUSED(event)
qDebug() << "Widget键盘按下事件";
}
mylineedit.h代码:
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget * parent = nullptr);
protected:
bool event(QEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
};
#endif // MYLINEEDIT_H
mylineedit.cpp代码:
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
MyLineEdit::MyLineEdit(QWidget *parent)
: QLineEdit(parent)
{
}
bool MyLineEdit::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "MyLineEdit的event()函数";
}
return QLineEdit::event(event);
}
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "MyLineEdi键盘按下事件";
QLineEdit::keyPressEvent(event);
event->ignore();
}
键盘上输入一个数字,或者字母
用图来表示事件的传播顺序:
对于事件过滤器的使用方法:
先在父窗口中注册需要安装接收某消息的控件安装事件过滤器:
m_lineEdit->installEventFilter(this);
然后重写父窗口的
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
if (obj == m_lineEdit)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "Widget的事件过滤器";
// return true;
}
}
return QWidget::eventFilter(obj, event);
}
return true表示事件已经得到了处理,不必继续传播。(大家可以将return true;的注释去掉看看,会看到只会输出 “Widget的事件过滤器” 后消息就不再被传播了。)
return false表示事件需要继续传递。
return QWidget::eventFilter(obj, event);
这样写,是调用父类的eventFilter,也就是继续传播事件。
当过滤器的 eventFilter() 实现被调用的时候, 它就可以选择是处理该事件,还是转发该事件, 或禁止该事件继续被其它对象处理. 若所有的事件过滤器都允许一个事件可被继续处理( 每个过滤器处理后都返回 false ), 该事件最终将被发送到目标对象. 如果其中一个中止了这个流程(通过返回 true)。
文中的示例放在了百度云盘上:(大家有什么好的建议,我可以放到其他地方去。csdn下载太贵,要方便大家免费下载示例)
链接:https://pan.baidu.com/s/1GY7vrmpHkud7AnBi4uX2zw
提取码:om1l
参考:
Qt学习之路27–事件传递过程和事件过滤器
Qt学习之路26–事件处理、事件重写、关闭文本编辑器操作
详解 QT Event 以及 Event Filter 事件处理