03_Qt的事件传递、消息过滤器和消息通知(类与类之间通讯)

一、事件传递

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();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值