特点:
基于操作系统才能运行;
GUI应用程序提供的功能必须由用户触发;
用户操作界面时操作系统是第一个感知的 ;
系统内核的消息通过事件处理转变成QT的信号。
(1)在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 事件处理的核心包括事件产生、分发、接受和处理。
①事件的产生
问题:谁来产生事件?
最容易想到的是我们的输入设备,比如键盘、鼠标产生的keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他们被封装成QMouseEvent和QKeyEvent)。
②Qt中事件的分发
问题:谁来负责分发事件?
对于non-GUI的Qt程序,是由QCoreApplication负责将QEvent分发给QObject的子类-Receiver.;对于Qt GUI程序,由QApplication来负责。
③事件的接受和处理
问题:谁来接受和处理事件?
答案是QObject。类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责(内存管理、内省(intropection)与事件处理制)之一。任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父类。
(2)Qt平台将系统产生的消息转变成Qt事件
A. Qt事件是一个QEvent(或子类)的对象;
B. 有时一个事件包含多个事件类型,比如鼠标事件又可以分为鼠标按下、双击、和移动多种操作事件类型由QEvent类的枚举型QEvent::Type来表示,可由帮助文档进行查询;
C. Qt事件用于描述程序内部或外部发生的对应动作(描述的是操作系统发生来的消息,一个系统消息对应着一个消息事件);
D. 任意QObject对象都具备时间处理的能力.
note:QEvent子类可以表示一个事件,但并不能处理这个事件
Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler)。如上所述,event()函数主要用于事件的分发。
(3)GUI应用程序的事件处理方式
A. Qt事件产生后会立即被分发到QWidget对象(QObject的子类,如按键QPushButton对象等);
B. QWidget对象其内部会有一个event(QEVent*)函数被调用,进行事件处理;
C. event()根据事件类型调用不同的事件处理函数(默认的子函数);
D. 在事件处理函数中发送Qt中预定义的信号;
E. 调用信号关联的槽函数。
(4) QPushButton事件处理分析
①接收到鼠标事件
②QApplication调用QObject::event(QEvent*)成员函数来处理,进行事件的分派。
③调用QPushButton的mouseReleaseEvent(QMouseEvent*)成员函数
④QPushButton调用click()成员函数
⑤触发信号SIGNAL(clicked())
(5)实例
实例一:自定义事件处理函数
鼠标左键右键
wigth.h
#ifndef WIDGET_H
#define WIDGET_H
#include
class Widget : public QWidget
{
Q_OBJECT
protected:
void mousePressEvent(QMouseEvent *event);
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
widgth.cpp
#include "widget.h"
#include
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
qDebug()<<"LeftButton clicked!";
}
else if(event->button()==Qt::RightButton)
{
qDebug()<<"RightButton clicked!";
}
}
Widget::~Widget()
{
}
main.cpp
#include
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
实例二:自定义事件处理函数
QMyPushButton.h
#ifndef _QMYPUSHBUTTON_H_
#define _QMYPUSHBUTTON_H_
#include
typedef void (QButtonListener)(QObject*,QMouseEvent*);
class QMyPushButton : public QPushButton
{
Q_OBJECT
protected:
QButtonListener* m_listener;
//重写QPushButton的事件处理函数 就有可能不会产生clicked信号
void mouseReleaseEvent(QMouseEvent *e);
public:
explicit QMyPushButton(QWidget* parent = 0, QButtonListener* listener = 0);
};
#endif // _QMYPUSHBUTTON_H_
QMyPushButton.cpp
#include "QMyPushButton.h"
#include
QMyPushButton::QMyPushButton(QWidget* parent, QButtonListener* listener):QPushButton(parent)
{
m_listener = listener;
}
//重写改写事件处理函数,会改变程序的行为。
void QMyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
if(m_listener != NULL)
{
//调用自定义的事件处理函数,尽管按钮的clicked信号被连接到onMyButtonClicked槽函数,
//但因自定义的m_listener函数里并不触发clicked信号,从而槽函数不会被调用。
m_listener(this, e);
e->accept();//事件被接收,就不再传递到父QWidget
setDown(false); //按钮设置为“弹起”状态
}
else
{
//父类的mouseReleaseEvent会去调用clicked(),并触发SIGNAL(clicked())
//从而调用到连接到该信号的槽函数(本例为onMyButtonClicked())
QPushButton::mouseReleaseEvent(e); //调用父类
}
}
Widget.h
#ifndef _WIDGET_H_
#define _WIDGET_H_
#include
#include "QMyPushButton.h"
class Widget : public QWidget
{
Q_OBJECT
QMyPushButton myButton;
protected slots:
void onMyButtonClicked();
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // _WIDGET_H_
Widget.cpp
#include "Widget.h"
#include
//自定义事件处理函数
void onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)
{
qDebug() << "onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)";
}
Widget::Widget(QWidget *parent)
: QWidget(parent),myButton(this, onMyButtonMouseRelease) //实验2:myButton(this, 0)
{
myButton.setText("QMyPushButton");
connect(&myButton, SIGNAL(clicked()), this, SLOT(onMyButtonClicked()));
}
//槽函数,用于接收按钮的clicked信号
void Widget::onMyButtonClicked()
{
qDebug() << "onMyButtonClicked()" ;
}
Widget::~Widget()
{
}
main.cpp
#include "Widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
(6)事件(QEvent)和信号(SIGNAL)的不同
例如:单击界面上的按钮,那么就会产生鼠标事件QMouseEvent(不是按钮产生的),由于按钮被按下了,所以他会发出一个单击信号clicked()信号(是按钮产生的),这里只考虑单击信号而不用考虑鼠标事件,但如果要设计一个按钮,或者当单击按钮时让它产生别的效果,此时就要考虑鼠标事件了,由此,信号和事件是两个不同层面的东西,发出者不同,作用不同。Qt中,所有的QObject的子类实例均可对事件接收和处理!
(1)Qt中的事件和信号不同
(2)事件由QObject对象进行处理
(3)信号由QObject对象触发
(4)重写事件处理函数可能改变程序行为
(5)信号的触发不会对程序行为造成影响
(6)事件处理是在实际工程开发中应用非常普遍的