一、QT事件管理
在Qt中主要由QApplication、QGUIApplication、QCoreApplication三个类来管理处理事件,具体的继承关系如下
QObject:所有Qt对象的基类。
QCoreApplication:主要用于提供无GUI程序的事件循环。
QGUIApplication:QGuiApplication类管理GUI应用程序的控制流和主要设置。它包含了主事件循环,所有来自窗口系统和其他源的事件都被处理和分派。它还处理应用程序的初始化和终结,并提供会话管理。
QApplication:QApplication专门为QGuiApplication提供了一些基于qwidget的应用程序所需的功能。
以上类在qt帮助文档中有讲述,可以查看帮助文档获取更多信息。
二、事件传递
Qt中的事件循环捕获各种事件,并将对应事件转化为带有事件信息的对象,然后由Qt的事件处理流程分发给需要处理事件的对象来处理事件。
其中exec()用于启动事件主循环,从事件队列中取出事件并创建一个对应的QEvent对象或其子对象来表示改事件;notify()函数对事件进行传递,最终由QObject::event()接收事件,event()负责将事件传递给目标对象并调用对应的事件处理函数。
传递规则如下:
若事件未被目标对象处理则不断向父类传递,如图所示
假设目标对象是四级窗口,信号在未被处理时会一直向父对象传递,直到被处理或者达到最顶层父对象为止。
三、事件处理
1、重写QWidget中接收事件处理函数
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QDebug>
class A : public QWidget
{
public:
void mousePressEvent(QMouseEvent *event){
qDebug() << "mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "mouse release";
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
A test;
test.resize(400, 400);
test.show();
return a.exec();
}
这种方式比较简单,鼠标的信息,比如按下左键、右键、位置信息…可以看QMouseEvent中提供的方法。
2、重写event函数
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QDebug>
class A : public QWidget
{
public:
bool event(QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << "QEvent KeyPress";
return 1;
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << "QEvent KeyRelease";
return QWidget::event(event);
}
}
void mousePressEvent(QMouseEvent *event){
qDebug() << "mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "mouse release";
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
A test;
test.resize(400, 400);
test.show();
return a.exec();
}
这里运行代码,点击鼠标打印信息如下:
可见mousePressEvent这个函数没有执行,主要是我们之间返回了没有将事件继续交由父类QWidget处理。
3、重写notify函数(不建议使用,这里举例只是为了说明整个事件处理流程)
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QDebug>
class A : public QWidget
{
public:
bool event(QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << "QEvent KeyPress";
return 1;
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << "QEvent KeyRelease";
return QWidget::event(event);
}
}
void mousePressEvent(QMouseEvent *event){
qDebug() << "mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "mouse release";
}
};
class B : public QApplication
{
public:
B(int argc, char *argv[]):QApplication(argc, argv){}
bool notify(QObject *object, QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << "notify QEvent::KeyPress";
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << "notify QEvent::KeyRelease";
}
return QApplication::notify(object, event);
}
};
int main(int argc, char *argv[])
{
B a(argc, argv);
A test;
test.resize(400, 400);
test.show();
return a.exec();
}
运行代码,点击鼠标打印信息如下:
可以看到输出信息跟信息传递描述的流程是一致的。
4、事件过滤器
使用事件过滤器主要有两个步骤,一是重写事件过滤这个函数,二是为需要使用事件过滤的控件安装事件过滤器。代码如下
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QDebug>
#include <QPushButton>
class A : public QWidget
{
public:
bool event(QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << "QEvent KeyPress";
return QWidget::event(event);
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << "QEvent KeyRelease";
return QWidget::event(event);
}
}
void mousePressEvent(QMouseEvent *event){
qDebug() << " widget mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "widget mouse release";
}
};
class B : public QPushButton
{
public:
B(QString text):QPushButton(text){}
void mousePressEvent(QMouseEvent *event){
qDebug() << "pushbutton mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "pushbutton mouse release";
}
};
class filter : public QObject
{
public:
bool eventFilter(QObject *watched, QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << watched->objectName() << ":mouse press";
return 0;
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << watched->objectName() << ":mouse release";
return 0;
}
return 0;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
A test;
B button1(QString("button1"));
filter fi;
test.setObjectName(QString("widget"));
button1.setParent(&test);
button1.setObjectName(QString("button1"));
button1.move(100, 200);
test.installEventFilter(&fi);
button1.installEventFilter(&fi);
test.resize(400, 400);
test.show();
return a.exec();
}
运行程序,依次点击widget界面和按钮,输出信息如下
由1可以看到过滤器是在event()前进行处理的,eventFilter中返回1表示该事件不再进一步进行处理,也就不会传到event中去;返回0表示交给目标对象处理。目前这里返回值为1,所以会继续传递。这里与event()中返回值含义类似。
四、事件接收和忽略
接收事件QEvent::accept(),忽略事件QEvent::ignore(),接收事件后事件将不再继续传递,这里我们用个例子看看。
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QDebug>
#include <QPushButton>
#include <QMouseEvent>
class A : public QWidget
{
public:
bool event(QEvent *event){
if(event->type() == QEvent::MouseButtonPress){
qDebug() << "QEvent KeyPress";
return QWidget::event(event);
}
if(event->type() == QEvent::MouseButtonRelease){
qDebug() << "QEvent KeyRelease";
return QWidget::event(event);
}
}
void mousePressEvent(QMouseEvent *event){
qDebug() << " widget mouse pressed";
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "widget mouse release";
}
};
class B : public QPushButton
{
public:
B(QString text):QPushButton(text){}
void mousePressEvent(QMouseEvent *event){
qDebug() << "pushbutton mouse pressed";
event->accept();
}
void mouseReleaseEvent(QMouseEvent *event){
qDebug() << "pushbutton mouse release";
event->accept();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
A mainWidget;
B button(QString("button"));
mainWidget.setObjectName(QString("main widget"));
button.setParent(&mainWidget);
button.move(100, 200);
mainWidget.resize(400, 400);
mainWidget.show();
return a.exec();
}
我们点击按钮后打印如下
主要是因为我们在B类中接受了鼠标事件,我们将event->accept();改成event->ignore();后运行点击按钮,输出信息如下
可以看到信号传到了父对象中,这里只有两层,如果有多层关系的话也是类似。