qt中sendEvent()、postEvent()用法

55 篇文章 27 订阅

QT-事件发送函数sendEvent()、postEvent()

-阻塞型事件发送

  • 需要重写接收对象的event()事件处理函数
  • 当事件发送后,将会立即进入event()事件处理函数进行事件处理
  • 通过sendEvent()静态函数实现阻塞发送:
 
  1. bool QApplication::sendEvent ( QObject * receiver, QEvent * event ) ;
  2. // receiver:接收对象, event :要发送的event类型(比如:鼠标双击)
  3. //当有事件发送,将会调用receiver对象里的event()成员函数进行事件处理
  • sendEvent()函数是阻塞式的,所以支持栈空间/堆空间事件对象的发送(局部对象和new分配的对象)
  • new分配的事件对象被处理后,会由Qt内部自动摧毁

-非阻塞型事件发送

  • 需要重写接收对象的event()事件处理函数
  • 当事件发送后立即返回,事件将会发送到事件队列中等待处理
  • 通过postEvent()静态函数实现非阻塞发送:
 
  1. void QApplication::postEvent ( QObject * receiver, QEvent * event );
  • postEvent()函数是非阻塞式的,所以只能支持栈堆空间事件对象的发送(new分配的对象)
  • new分配的事件对象被处理后,会由Qt内部自动摧毁

示例-通过sendEvent()发送预定义的键盘Delete按键事件

Wiget.h

 
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. #include <QtGui>
  5. class Widget : public QWidget
  6. {
  7. Q_OBJECT
  8. private :
  9. QTextEdit edit;
  10. QPushButton bt;
  11. private slots:
  12. void onPushButton();
  13. public:
  14. explicit Widget();
  15. };
  16. #endif // WIDGET_H

Widget.c

 
  1. #include "widget.h"
  2. Widget::Widget() : edit(this),bt("Delete",this)
  3. {
  4. edit.setGeometry(,,,);
  5. bt.setGeometry(,,,);
  6. connect(&bt, SIGNAL(clicked()), this, SLOT(onPushButton()));
  7. }
  8. void Widget::onPushButton()
  9. {
  10. int key = Qt::Key_Delete ;
  11. QKeyEvent EventPress(QEvent::KeyPress,key,Qt::NoModifier);
  12. QApplication::sendEvent(&edit,&EventPress); //发送键盘按下事件
  13. QKeyEvent EventRelease(QEvent::KeyRelease,key,Qt::NoModifier);
  14. QApplication::sendEvent(&edit,&EventRelease); //发送键盘松开事件
  15. }

效果

 

 

自定义事件对象

  • 自定义的事件类必须继承自QEvent,并且无需指定父类
  • 自定义的事件类必须拥有全局唯一Type值,使用QEvent::User+value即可
  • 自定义事件类示例:
 
  1. class StringEvent : public QEvent
  2. {
  3. public:
  4. static const Type = static_cast<Type>(QEvent::User+0x10);
  5. explicit QStringEvent();
  6. //... ...
  7. }
  8. QStringEvent::QStringEvent() :
  9. QEvent(TYPE) //注册TYPE值
  10. {
  11. //... ...
  12. }
  • 由于Qt不认识自定义事件,所以程序里需要提供处理自定义事件对象的方法

常用两种方法来处理

1.通过事件过滤器处理

  • 通过installEventFilter()安装到目标对象
  • eventFilter()函数里处理事件

2.重写目标对象的event()函数

  • event ()函数里处理事件

 

示例-通过单击鼠标按钮发送自定义事件QStringEvent

QStringEvent文件:

 
  1. class QStringEvent : public QEvent
  2. {
  3. private:
  4. QString mstr;
  5. public:
  6. const static Type TYPE = static_cast<Type>(QEvent::User+0x10);
  7. explicit QStringEvent(QString s);
  8. QString str();
  9. };
  10. QStringEvent::QStringEvent(QString s) :
  11. QEvent(TYPE)
  12. {
  13. mstr = s;
  14. }
  15. QString QStringEvent::str()
  16. {
  17. return mstr;
  18. }

widget文件:

 
  1. class Widget : public QWidget
  2. {
  3. private :
  4. QLabel label;
  5. bool event( QEvent * e);
  6. bool eventFilter(QObject *obj, QEvent *event);
  7. public:
  8. explicit Widget();
  9. };
  10. Widget::Widget() : label(this)
  11. {
  12. label.installEventFilter(this);
  13. }
  14. bool Widget::event( QEvent * e)
  15. {
  16. if(e->type() == QEvent::MouseButtonPress)
  17. {
  18. QMouseEvent *me = dynamic_cast<QMouseEvent* >(e);if(me->button() == Qt::LeftButton)
  19. {
  20. QStringEvent event( QString("X坐标: %1 Y坐标: %2").arg(me->x()).arg(me->y()) );
  21. QApplication::sendEvent(&label,&event); //发送自定义事件
  22. }
  23. }
  24. return QWidget::event(e);
  25. }
  26. bool Widget::eventFilter(QObject *obj, QEvent *event)
  27. {
  28. QLabel *t = dynamic_cast<QLabel* >(obj);
  29. if(t && event->type()== QStringEvent::TYPE )
  30. {
  31. QStringEvent *str = dynamic_cast<QStringEvent* >(event);
  32. t->setText(str->str());
  33. t->adjustSize();
  34. return true;
  35. }
  36. return QWidget::eventFilter(obj,event);
  37. }

效果:

 

/***********************************************************************

Qt中的消息通知和事件发送

Qt中的信号和槽机制、事件机制是其具有特色的两大机制。利用这两种机制可以轻松地实现需要的消息通知和事件通知。

1、信号和槽机制

充分使用Qt库中已经定义和实现好的对象的信号和槽函数,如按钮的clicked()/pressed()信号等,它们能满足很多的需求;

自定义缺乏的信号和槽函数,借助Qt的元对象系统和内省机制,在创建类时添加Q_OBJECT宏,使用signals:/slots:标记添加自定义的信号/槽函数,使用时通过emit发送信号,用connect()函数连接信号和槽。

2、事件机制

充分使用Qt库中已经定义好的标准事件对象,如鼠标事件QMouseEvent、键盘事件QKeyPressEvent等,自定义实现事件的处理函数,如keyPressEvent(QEvent*);

自定义需要的事件类型和实现QObject::customEvent(QEvent*)函数,使用Qt的postEvent和sendEvent函数发送事件通知。

(1)、自定义事件:

方式一;通过QEvent::Type指定事件类型的值,然后new一个该类型的自定义事件,如:

const QEvent::Type MyEvent = (QEvent::Type)9393;

QApplication::postEvent(object, new QCustomEvent(MyEvent));

【QCustomEvent类是Qt3中的类,现在已经不推荐使用了。】

QEvent::Type是Qt中的枚举类型,Qt定义了一大堆的库事件类型常数值,当然也允许用户自定义自己的事件类型值,但是自定义的值应大于1000(QEvent::User),且小于65535(QEvent::MaxUser).方便起见,可以使用int QEvent::registerEventType ( int hint = -1 ) [static]函数注册和保留一个自定义的事件类型值,这样可以避免不小心重复使用了同一个事件类型值,它保证每次得到一个未被使用的事件类型常数值,该函数是线程安全的,在Qt4.4中引入。

方式二:通过继承QEvent创建新的事件类,如:

class CMyCustomEvent:public QEvent

{

public:

CMyCustomEvent(int data):m_iData(data),QEvent((QEvent::Type)9393){}

private:

int m_iData;

...

};

(2)、发送事件:postEvent/sendEvent/notify

postEvent函数:void QCoreApplication::postEvent ( QObject * receiver, QEvent * event ) [static]【异步】

将事件放入事件消息队列中,然后立即返回,函数只将事件放入队列的尾端,不保证事件立即得到处理。事件必须是分配在堆上的,即new出来的,因为在事件被发送出去后,事件队列就拥有了事件的,事件处理完后Qt会自动delete该事件,因此在把事件posted出去后再尝试使用它是不安全的。

当程序控制到达主事件循环时,事件队列中的所有事件才用notify函数发送。事件的处理是按照其发送到队列中的顺序进行的,如果想要控制事件的优先级,可以考虑它的带优先级参数的重载函数。

void QCoreApplication::postEvent ( QObject * receiver, QEvent * event, int priority ) [static]【Qt4.3引入】

这两个函数都是线程安全的。

sendEvent函数:bool QCoreApplication::sendEvent ( QObject * receiver, QEvent * event ) [static]【同步】

用notify函数将事件直接派发给接收者和进行处理,返回事件处理者的返回值。事件会立即送至接受者,被发送后,Qt不会自动delete该事件,因此合适的做法是在栈上创建事件。

sendPostedEvents:

void QCoreApplication::sendPostedEvents ( QObject * receiver, int event_type ) [static]

将事件队列中用postEvent函数放入的对应接受者和事件类型的事件立即分发,但是来自窗口系统的事件不被分发,它们被processEvents()函数分发。

如果接受者是null,则对应所有的接受者;如果event_type为0,则对应receiver的所有的事件。该函数必须和receiver在同一个线程内被调用。

void QCoreApplication::sendPostedEvents () [static]

分发事件队列中的所有事件,即清空事件队列。

notify:bool QCoreApplication::notify ( QObject * receiver, QEvent * event ) [virtual]

这是事件机制中最基本的函数,所有的事件发送最终都要调用这个函数。它把事件信号发送给接受者,并返回receiver->event(event)处理的返回值。

(3)、处理事件:void QObject::customEvent ( QEvent * event ) [virtual protected]

通过重载实现customEvent函数,可以对自定义的事件进行灵活的处理,如:

void MyWidget::customEvent(QEvent *event)

{

if (event->type() == MyCustomEvent)

{

QMessageBox msgBox;

msgBox.setText("The is mycustomevent example.");

msgBox.exec();

}

else if(...)

{

...

}

...

}
/***************************************************

1. sendEvent(QObject* receiver,QEvent* event)

    使用notify()函数直接给receiver发送事件,也就是同步处理事件。

2. postEvent(QObject* receiver, QEvent* event)

   向事件队列中添加receiver和event,对应异步处理事件。

3.QObject::customEvent(QEvent *e)

   处理多个Qt事件处理函数,可以通过重载QObject::event()来实现。
/**************************************************************

Qt 自定义事件(三种方法:继承QEvent,然后Send Post就都可以了,也可以覆盖customEvent函数,也可覆盖event()函数)

Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展。在 Qt 中,你需要继承的类是 QEvent。

继承QEvent类,你需要提供一个QEvent::Type类型的参数,作为自定义事件的类型值。这里的QEvent::Type类型是QEvent里面定义的一个enum,因此,你是可以传递一个int的。重要的是,你的事件类型不能和已经存在的type值重复,否则会有不可预料的错误发生!因为系统会将你的事件当做系统事件进行派发和调用。在Qt中,系统将保留0 - 999的值,也就是说,你的事件type要大于999. 具体来说,你的自定义事件的type要在QEvent::User和QEvent::MaxUser的范围之间。其中,QEvent::User值是1000,QEvent::MaxUser的值是65535。从这里知道,你最多可以定义64536个事件,相信这个数字已经足够大了!但是,即便如此,也只能保证用户自定义事件不能覆盖系统事件,并不能保证自定义事件之间不会被覆盖。为了解决这个问题,Qt提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名如下:

static int QEvent::registerEventType ( int hint = -1 );

函数是static的,因此可以使用QEvent类直接调用。函数接受一个int值,其默认值为-1,返回值是创建的这个Type类型的值。如果hint是合法的,不会发生任何覆盖,则会返回这个值;如果hint不合法,系统会自动分配一个合法值并返回。因此,使用这个函数即可完成type值的指定。这个函数是线程安全的,因此不必另外添加同步。

你可以在QEvent子类中添加自己的事件所需要的数据,然后进行事件的发送。Qt中提供了两种发送方式:

  • static bool QCoreApplication::sendEvent(QObjecy * receiver, QEvent * event):事件被QCoreApplication的notify()函数直接发送给receiver对象,返回值是事件处理函数的返回值。使用这个函数必须要在栈上创建对象,例如:
    QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
    QApplication::sendEvent(mainWindow, &event);
  • static bool QCoreApplication::postEvent(QObject * receiver, QEvent * event):事件被QCoreApplication追加到事件列表的最后,并等待处理,该函数将事件追加后会立即返回,并且注意,该函数是线程安全的。另外一点是,使用这个函数必须要在堆上创建对象,例如:
    QApplication::postEvent(object, new MyEvent(QEvent::registerEventType(2048)));
    这个对象不需要手动delete,Qt会自动delete掉!因此,如果在post事件之后调用delete,程序可能会崩溃。另外,postEvent()函数还有一个重载的版本,增加一个优先级参数,具体请参见API。通过调用sendPostedEvent()函数可以让已提交的事件立即得到处理。

如果要处理自定义事件,可以重写QObject的customEvent()函数,该函数接收一个QEvent对象作为参数。注意,在Qt3中这个参数是QCustomEvent类型的。你可以像前面介绍的重写event()函数的方法去重写这个函数:

void CustomWidget::customEvent(QEvent *event) {
        CustomEvent *customEvent = static_cast<CustomEvent *>(event);
        // ....
}


另外,你也可以通过重写event()函数来处理自定义事件:

bool CustomWidget::event(QEvent *event) {
        if (event->type() == MyCustomEventType) {
                CustomEvent *myEvent = static_cast<CustomEvent *>(event);
                // processing...
                return true;
        }

        return QWidget::event(event);
}

这两种办法都是可行的。

另附Qt中GlobalColor表格:

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值