[Qt] postevent emit

      最近在为bestv做一个播放的plugin,这个plugin主要是在Qt中完成play等功能并能在JavaScript里面进行调用,其中里面就遇到了信息、事件等问题。开始时,我选择通过connect关联singal和slots,再利用emit来触发信息,从而达到执行和回调信息给JavaScript的作用(之所以选择这种,其中一个主要的因素,就是设计plugin类的哥们定义了event处理方式,就是emit方式——从而,我也觉得此种方式可以完成Qt Object 和JSObject的回调等交互与信号传输)。不过,发现此类方式的singal触发时序很难控制并且bestv方在对singal接受部分,并未有完善的方案,最后,只好放弃emit、选择postevent。下面转载、整理、分享了一些来源于网络的Qt-event相关的文档。

------------------------------------------------------------------------------------

Qt中抛消息有:信号和槽、postEvent、sentEvent等机制,sentEvent只支持同步的。postEvent可以实现异步的,其机制是将消息发送到消息队列中,消息队列又会把这些消息都抛出(当然要实现该功能我们也可以用信号和槽机制,将connect函数的最后一个参数设置为Qt::QueuedConnection即可)。

言归正传,上段我们说到消息队列把消息抛出来,我们该如何去捕获该消息呢?我们只要实现父类中的event()或者customEvent()函数即可,在里面实现我们自己的处理,在此建议采用customEvent()。

以下是一个简单的实例:

#include <QWidget>
#include <QEvent>

const QEvent::Type CustomEvent_Login = (QEvent::Type)5001;//建议用5000以上唯一的标识


class PostEvent : public QWidget
{
Q_OBJECT

public:
PostEvent(QWidget *parent = 0);
~PostEvent();

private:
void customEvent(QEvent *e);   //该函数是父类QWidget的虚函数

};

PostEvent::PostEvent(QWidget *parent)
{
QApplication::postEvent(this, new QEvent(CustomEvent_Login));   //该函数实现将自定义的消息发送到队列,且new QEvent(CustomEvent_Login))只能动态分配,原因请看Qt的帮助文档中的postEvent函数说明。
}

void PostEvent::customEvent(QEvent *e)
{
if (e->type() == CustomEvent_Login)   //捕获消息
{
   QMessageBox msgBox;
   msgBox.setText("The document has been modified.");
   msgBox.exec();
}
}

呵呵,就这样吧 本人一开始犯了一个很白痴的错误,即把customEvent函数当作用户可以自定义的函数,殊不知是父类中的虚函数,所以一直捕获不到消息。好了,以上只是一个简单的关于postEvent的一个应用,如果想了解更多的消息机制请阅读其他关于event的文章。
/*
其实对于event的处事方式,最著名的就是两种,一是事件冒泡法(event bubbing),即:事件开始时,由event送至各事件接收方,IE浏览器的研发团队就是采用此方法;另一是事件捕获(event capturing),即事件接收方主动去捕获event。
*/

-------------------------------------------------------------------------------------

qt event 是Qt中最重要的概念之一,是因为Qt程序是典型的事件驱动型, 程序的每个动作都是由幕后某个事件所触发. Qt事件的类型很多, 常见的qt的事件如下:

§          键盘事件: 按键按下和松开.

§          鼠标事件: 鼠标移动,鼠标按键的按下和松开.

§          拖放事件: 用鼠标进行拖放.

§          滚轮事件: 鼠标滚轮滚动.

§          绘屏事件: 重绘屏幕的某些部分.

§          定时事件: 定时器到时.

§          焦点事件: 键盘焦点移动.

§          进入和离开事件: 鼠标移入widget之内,或是移出.

§          移动事件: widget的位置改变.

§          大小改变事件: widget的大小改变.

§          显示和隐藏事件: widget显示和隐藏.

§          窗口事件: 窗口是否为当前窗口.

      Qt 的事件和 Qt 中的 signal 不一样 ,  后者通常用来 " 使用 "widget,  而前者用来 " 实现 " widget。 比如一个按钮 我们使用这个按钮的时候 ,  我们只关心他 clicked() signal, 至于这个按钮如何接收处理鼠标事件 再发射这个信号 我们是不用关心的 但是如果我们要重载一个按钮的时候 , 我们就要面对 event 比如我们可以改变它的行为 在鼠标按键按下的时候 (mouse press event)  就触发 clicked()  signal 而不是通常在释放的 ( mouse release event) 时候。如下图给出event处理过程的示意图。

    由图可知:
  一、postevent是将event提交到event队列中,交给Qt去处理,至于如何处理,并不关心也不参与;
  二、event一般只有两个来源,1)是系统产生, 通常是指window system把从系统得到的消息比如鼠标按键,键盘按键等放入系统的消息队列中,Qt事件循环的时候读取这些事件转化为QEvent,再依次处理。2)Qt应用程序程序自身产生的程序产生事件有两种方式一种是调用QApplication::postEvent(). 例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中等待依次被处理另一种方式是调用sendEvent()函数这时候事件不会放入队列而是直接被派发和处理, QWidget::repaint()函数用的就是这种方式
  三、event处理的方式,即event的提交与处理的调度也有两种:一是同步的,一是异步。

Qt的事件循环是异步的,当调用QApplication::exec()时,就进入了事件循环. 该循环可以简化的描述为如下的代码:

while (!app_exit_loop ) {

       while( !postedEvents ) {             processPostedEvents()       }
       while( !qwsEvnts ){            qwsProcessEvents();   }
       while( !postedEvents ) {             processPostedEvents()       }

}

先处理Qt事件队列中的事件, 直至为空. 再处理系统消息队列中的消息,直至为空, 在处理系统消息的时候会产生新的Qt事件, 需要对其再次进行处理.

调用QApplication::sendEvent的时候, 消息会立即被处理,是同步的. 实际上QApplication::sendEvent()是通过调用QApplication::notify(), 直接进入了事件的派发和处理环节。
---------------------------------------------------------------------------------
事件过滤器:
    事件过滤器是Qt中一个独特的事件处理机制,功能强大而且使用起来灵活方便.通过它,可以让一个对象侦听拦截另外一个对象的事件.事件过滤器是这样实现的:在所有Qt对象的基类: QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObjec(qobjA)给另一个QObject (qobjB)安装了事件过滤器之后, qobjB会把qobjA的指针保存在eventFilters.qobjB处理事件之前,会先去检查eventFilters列表,如果非空,就先调用列表中对象的eventFilter()函数.一个对象可以给多个对象安装过滤器.同样,一个对象能同时被安装多个过滤器,在事件到达之后,这些过滤器以安装次序的反序被调用.事件过滤器函数( eventFilter() )返回值是bool,如果返回true,则表示该事件已经被处理完毕, Qt将直接返回,进行下一事件的处理;如果返回false,事件将接着被送往剩下的事件过滤器或是目标对象进行处理.
---------------------------------------------------------------------------------

根据对Qt事件机制的分析, 我们可以得到5种级别的事件过滤,处理办法. 以功能从弱到强, 排列如下:

1 重载特定事件处理函数.

最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent()这样的特定事件处理函数. 以按键事件为例, 一个典型的处理函数如下:

void imageView::keyPressEvent(QKeyEvent* event)
{
switch (event->key()) {
case Key_Plus:
zoomIn();
break;
case Key_Minus:
zoomOut();
break;
case Key_Left:
// …
default:
QWidget::keyPressEvent(event);
}
}  

2重载event()函数.

通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件(比如:LayoutDirectionChange)时,evnet()也很有用,因为这些函数没有相应的特定事件处理函数. 当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件.

下面这个例子演示了如何重载event()函数, 改变Tab键的默认动作: (默认的是键盘焦点移动到下一个控件上. )

bool CodeEditor::event(QEvent * event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = (QKeyEvent *) event;
if (keyEvent->key() == Key_Tab) {
insertAtCurrentPosition('/t');
return true;
}
}
return QWidget::event(event);
}

3 在Qt对象上安装事件过滤器.

安装事件过滤器有两个步骤:(假设要用A来监视过滤B的事件)

首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.

 然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码.

用这种方法改写上面的例子:(假设我们将CodeEditor 放在MainWidget中)

MainWidget::MainWidget()

{

       // …

CodeEditor * ce = new CodeEditor( this, “codeeditor”);

ce->installEventFilter( this );

// …

}

bool MainWidget::eventFilter( QOject * target , QEvent* event )

{

       if( target== ce ){

              if(event->type() == QEvent::KeyPress ) {

                     QKeyEvent*ke = (QKeyEvent *) event;

                     if(ke->key() == Key_Tab ){

ce->insertAtCurrentPosition('/t');

return true;

                     }

              }

       }

       returnfalse;

}

4 给QAppliction对象安装事件过滤器.

一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个eventFilter().在debug的时候,这个办法就非常有用, 也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. ( 在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃)

5 继承QApplication类,并重载notify()函数.

Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法.通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件过滤器,相比之下, notify()函数只有一个.

--------------------------------------------------------------------------------

你可能感兴趣的:(JavaScript,object,文档,qt,login,Signal)