一、事件传递
1、Qt的事件传递是将当前触发的事件(可能是按键触发、键盘触发或是组合按键触发等)通过event函数来接收,将接收到的事件QEvent 在分类传递给各个相应的函数去处理,这样我们就不必再event中分出我们想要的消息类型,而是通过重写相应的函数去处理事件。
2、但是系统类中的event也不是万能的,可以有的事件没有分类到我们想要的函数中,这时就需要我们重写event函数提取我们想要的消息,然后处理。
3、注意:消息(事件)处理之后,要将消息传递下去,给其他控件捕获;如果不想其他控件捕获到的话,就必须对消息进行拦截;
4、布局上面的控件是可以设置焦点的,例如下面的按钮就设置了焦点,按下回车键则可以触发事件。前辈告诉我这个焦点也是可以设置等级的,还没测试过。
5、鼠标滑过自动检测也是一个函数,必须手动开启;
6、在自己的头文件中,必须加上qobject,slots , signals等宏,否则很容易出错。
#include "MyWidgetEvent.h"
MyWidgetEvent::MyWidgetEvent(QWidget *parent):count(0) {
QVBoxLayout *lay = new QVBoxLayout(this) ;
QPushButton *button1 ;
QPushButton *button2 ;
lay->addWidget( button1 = new QPushButton("Button01") ) ;
lay->addWidget( button2 = new QPushButton("Button02") ) ;
lay->addWidget( new QLineEdit() ) ;
button1->setDefault(true) ;//设置button自动获取到焦点
this->setMouseTracking(true) ;//这个设置当鼠标滑过时,自动检测到而不用单击或是按着
connect( button1 , SIGNAL( clicked() ) , this , SLOT( close() ) ) ;
connect( button2 , SIGNAL(clicked(bool)) , this , SLOT(slotButtonClicked()) ) ;
//QObject::connect: No such slot QWidget::总是报出这个错误,原来是自己声明的类中没加q_Object宏和private slot导致的,signal自己有写的话也要添加
}
void MyWidgetEvent::slotButtonClicked( ) {
QPushButton *button = (QPushButton*)this->sender() ;
qDebug()<<"chen"<<button->text() ;
}
MyWidgetEvent::~MyWidgetEvent(void) { }
bool MyWidgetEvent::event(QEvent *ev) {
if( ev->type()==QEvent::MouseButtonPress ) {
//QMouseEvent *mouseEv = (QMouseEvent*)ev;
/*
**控件所接收到的事件都是由event这个函数先接收到,之后才进行分类。
**例如:分为鼠标、键盘等,所以都写了特定的虚函数给子类重写。
**上面的这句代码是为了说明,事件传递进来之后,再转化为具体的子类事件,执行相应的函数。
**而这些事件判断的功能都不需要我们重写分发(特殊的也可以),通常情况下都有相应的函数了。
**只要重写相应的函数即可。
*/
++count ;
qDebug()<< QString(count) ;
//return true ;
//如果返回true,则表示事件已由当前控件处理,也称为拦截(拦截特定动作)
//这里我重写了下面的函数mousePressEvent函数,但是上面的return true(拦截),所以下面的函数接收不到事件,必须return ...(传递下去);
}
ev->accept() ;//通知其他控件,当前的事件我已经处理
return QWidget::event(ev) ;//没被拦截的事件继续传递下去;
//注意:一定要继续传递下去,不然后续的控件就接收不到事件了。
}
void MyWidgetEvent::mousePressEvent( QMouseEvent *ev) {
/*鼠标按下事件*/
QPoint pt = ev->pos() ;
qDebug()<<pt ;
if( ev->button()==Qt::LeftButton ) {
qDebug()<<"left button"<<endl ;
}
if( ev->modifiers()==Qt::ShiftModifier ) {
qDebug()<<"shift press"<<endl ;
}
if( ev->button()==Qt::LeftButton ){
if( ev->modifiers()==Qt::ControlModifier ) {
qDebug()<<"ctrl+leftbutton"<<endl ;
}
}
}
void MyWidgetEvent::mouseReleaseEvent( QMouseEvent *ev) {
/*鼠标弹起事件*/
qDebug()<<"release";
}
void MyWidgetEvent::mouseMoveEvent( QMouseEvent *ev) {
static int i=0 ;
/*鼠标移动事件,鼠标按着移动才触发
*但是在通常情况下,我们打开软件,当鼠标自动移动过去而不需要按着就能触发一些操作
*例如:爱奇艺软件,当鼠标滑过是字体自动变大。。。。
*这个怎么解决呢,看上面注释,找解决方法*/
qDebug()<<"mouse move"<<++i;
}
void MyWidgetEvent::mouseDoubleClickEvent(QMouseEvent *ev) {
/*
**这个鼠标双击事件不要使用,经常出错。
**要使用的话,使用mousePressEvent函数调试出双击的效果
*/
}
void MyWidgetEvent::keyPressEvent( QKeyEvent *ev) {
/*按键按下事件*/
ev->modifiers() ;
int key = ev->key() ;
qDebug()<<key<<"--"<<(char)key<<endl ;
}
void MyWidgetEvent::keyReleaseEvent( QKeyEvent *ev ) {
/*按键释放事件*/
qDebug()<<"key release"<<endl ;
}
void MyWidgetEvent::closeEvent( QCloseEvent *ev ) {
/*关闭窗口时调用的函数,主要用来释放一些资源*/
qDebug()<<"close windows"<<endl ;
}
void MyWidgetEvent::paintEvent( QPaintEvent *ev ) {
QPainter p(this) ;
p.drawLine( 50 , 50 , 80 , 80 ) ;
}
二、消息过滤器
1、 所谓消息过滤器,就是将自己捕获到的消息(事件)交给别人去处理,例如:下面的button控件接收到消息后,将自己的消息交给widget去处理(这样就可以不用重写button控件类的消息类型,很麻烦);
2、QApplications有自己的通知函数,在其上的控件接收到的消息都能通过这个通知函数QApplication::notify接收到相应的消息,进而可以进行相应的处理;
#include "MyWidgetEvent.h"
MyWidgetEvent::MyWidgetEvent(QWidget *parent) {
QPushButton *button = new QPushButton("good",this) ;
_button = button ;
button->installEventFilter(this) ;
/*
**这个是button的消息过滤器函数installEventFilter,
**通过这个函数,button会将自己的事件发送给参数this指定的对象的函数MyWidgetEvent::eventFilter
**通过这个函数,我们就可以直接在MyWidgetEvent中处理button的事件,而不用重写自己的button然后再写事件传递触发等函数
*/
}
bool MyWidgetEvent::eventFilter(QObject *o, QEvent *e) {
if( (QObject*)_button==o ) {
qDebug() << "button press " << endl ;
}
return QWidget::eventFilter( o , e ) ;//消息继续传递下去
}
MyWidgetEvent::~MyWidgetEvent(void) { }
/*这个演示QApplication类的notify函数的使用*/
#include "MyApplication.h"
MyApplication::MyApplication(int &argc, char **argv):QApplication(argc,argv) { }
MyApplication::~MyApplication(void) { }
bool MyApplication::notify( QObject *o, QEvent *e ) {
if( this->topLevelWidgets().count()>0 ){
QWidget *mainWnd = this->topLevelWidgets().at(0) ;
if( o==(QObject*)mainWnd && e->type()==QEvent::MouseButtonPress ){
//do youself
qDebug()<<"notify mouse press " ;
}
}
return QApplication::notify( o , e ) ;
}
三、消息通知
可以实现两个类之间的通讯,消息传递
#include "MyWidgetEvent.h"
MyWidgetEvent::MyWidgetEvent(QWidget *parent) { }
MyWidgetEvent::~MyWidgetEvent(void) { }
bool MyWidgetEvent::event( QEvent *ev ) {
if( ev->type() == QEvent::User ){
qDebug()<<"QWidget mouse press" ;
}
return QWidget::event( ev ) ;
}
/*这里通过qapplication类将消息发送给qwidget,然后再qwidget中进行相对应的处理*/
int main(int argc, char *argv[]) {
MyApplication a( argc , argv ) ;
MyWidgetEvent w ;
w.show() ;
qDebug() << "begin send";
a.postEvent(&w, new QEvent(QEvent::User));
qDebug() << "end send";
// app.sendEvent(&w, )
return a.exec();
}