Qt 鼠标过滤驱动,该如何处理

  处理监控系统的时候遇到问题,在MainWidget中创建多个子Widget的时候,原意是想鼠标点击先让MainWidget截获处理后再分派给子Widget去处理,但调试后发现如果子Widget重新实现了事件方法,就直接处理掉事件了,没有进到MainWidget的处理方法中去,如果子Widget没有accept或ignore该事件,则该事件就会被传递给其父亲,在子Widget存在accept或ignore事件的时候,想要经过一下MainWidget的处理方法,就得用到事件处理器,因此网上找了一下,发现QT的事件处理器可以处理。
  QT将事件封装为QEvent实例以后,会呼叫QObject的event()方法,并且将QEvent实例传送给它,在某些情况下,希望在执行event()之前,先对一些事件进行处理或过滤,然后再决定是否呼叫event()方法,这时候可以使用事件过滤器。
  可以重新定义一个继承自QObject(或其子类)的类的eventFilter()方法,
bool FilterObject::eventFilter(QObject *object, QEvent *event)
  if(event-&type() == QEvent::KeyPress)
  {&& & & &
    QKeyEvent *keyEvent = static_cast&QKeyEvent *&(event);&& & & &
    if (keyEvent-&key() == Qt::Key_Tab)&
      // 处理Tab键 & & & & &&
      && & &&
eventFilter()的object参数表示事件发生的来源物件,eventFilter()若返回false,则安装该事件过滤器的对象的event()会继续执行,若返回true,则安装事件过滤器的对象后event()方法就不会被执行,由此进行事件的拦截处理。给本对象安装事件过滤器:
this-&installEventFilter(this);
Qt事件的类型很多,&常见的qt的事件如下:
键盘事件:&按键按下和松开.
鼠标事件:&鼠标移动,鼠标按键的按下和松开.
拖放事件:&用鼠标进行拖放.
滚轮事件:&鼠标滚轮滚动.
绘屏事件:&重绘屏幕的某些部分.
定时事件:&定时器到时.
焦点事件:&键盘焦点移动.
进入和离开事件:&鼠标移入widget之内,或是移出.
移动事件: widget的位置改变.
大小改变事件: widget的大小改变.
显示和隐藏事件: widget显示和隐藏.
窗口事件:&窗口是否为当前窗口.
还有一些非常见的qt事件,比如socket事件,剪贴板事件,字体改变,布局改变等等.
Qt的事件和Qt中的signal不一样.&后者通常用来"使用"widget,&而前者用来"实现" widget.&比如一个按钮,&我们使用这个按钮的时候,&我们只关心他clicked()的signal,&至于这个按钮如何接收处理鼠标事件,再发射这个信号,我们是不用关心的.&但是如果我们要重载一个按钮的时候,我们就要面对event了.&比如我们可以改变它的行为,在鼠标按键按下的时候(mouse press event)&就触发clicked()的signal而不是通常在释放的( mouse release event)时候.
事件的产生
事件的两种来源:
&&&&&&&一种是系统产生的;通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等,&放入系统的消息队列中. Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.
&&&&&&&一种是由Qt应用程序程序自身产生的.程序产生事件有两种方式,&一种是调用QApplication::postEvent().&例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理.&另一种方式是调用sendEvent()函数.&这时候事件不会放入队列,&而是直接被派发和处理, QWidget::repaint()函数用的就是这种方式.
事件的调度
两种调度方式,一种是同步的,&一种是异步.
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中一个独特的事件处理机制,&功能强大而且使用起来灵活方便.&通过它,&可以让一个对象侦听拦截另外一个对象的事件.&事件过滤器是这样实现的:&在所有Qt对象的基类: QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObjec (qobjA)给另一个QObject (qobjB)安装了事件过滤器之后, qobjB会把qobjA的指针保存在eventFilters中.&在qobjB处理事件之前,会先去检查eventFilters列表,&如果非空,&就先调用列表中对象的eventFilter()函数.&一个对象可以给多个对象安装过滤器.&同样,&一个对象能同时被安装多个过滤器,&在事件到达之后,&这些过滤器以安装次序的反序被调用.&事件过滤器函数( eventFilter() )&返回值是bool型,&如果返回true,&则表示该事件已经被处理完毕, Qt将直接返回,&进行下一事件的处理;&如果返回false,&事件将接着被送往剩下的事件过滤器或是目标对象进行处理.
Qt中,事件的派发是从QApplication::notify()&开始的,&因为QAppliction也是继承自QObject,&所以先检查QAppliation对象,&如果有事件过滤器安装在qApp上,&先调用这些事件过滤器.&接下来QApplication::notify()&会过滤或合并一些事件(比如失效widget的鼠标事件会被过滤掉,&而同一区域重复的绘图事件会被合并).&之后,事件被送到reciver::event()&处理.
同样,&在reciver::event()中,&先检查有无事件过滤器安装在reciever上.&若有,&则调用之.&接下来,根据QEvent的类型,&调用相应的特定事件处理函数.&一些常见的事件都有特定事件处理函数,&比如:mousePressEvent(), focusOutEvent(),&&resizeEvent(), paintEvent(), resizeEvent()等等.&在实际应用中,&经常需要重载这些特定事件处理函数在处理事件.&但对于那些不常见的事件,&是没有相对应的特定事件处理函数的.&如果要处理这些事件,&就需要使用别的办法,&比如重载event()&函数,&或是安装事件过滤器.
事件的转发
&对于某些类别的事件,&如果在整个事件的派发过程结束后还没有被处理,&那么这个事件将会向上转发给它的父widget,&直到最顶层窗口.&如图所示,&事件最先发送给QCheckBox,&如果QCheckBox没有处理,&那么由QGroupBox接着处理,&如果QGroupBox没有处理,&再送到QDialog,&因为QDialog已经是最顶层widget,&所以如果QDialog不处理, QEvent将停止转发.
如何判断一个事件是否被处理了呢? Qt中和事件相关的函数通过两种方式相互通信. QApplication::notify(), QObject::eventFilter(), QObject::event()&通过返回bool值来表示是否已处理. &真&表示已经处理, &假&表示事件需要继续传递.&另一种是调用QEvent::ignore()&或&QEvent::accept()&对事件进行标识.&这种方式只用于event()&函数和特定事件处理函数之间的沟通.&而且只有用在某些类别事件上是有意义的,&这些事件就是上面提到的那些会被转发的事件,&包括:&鼠标,&滚轮,&按键等事件.
1.重载特定事件处理函数
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent()&这样的特定事件处理函数.&以按键事件为例,&一个典型的处理函数如下:
void imageView::keyPressEvent(QKeyEvent * event)
switch (event-&key()) {
case Key_Plus:
case Key_Minus:
zoomOut();
case Key_Left:
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 *)
if (keyEvent-&key() == Key_Tab) {
insertAtCurrentPosition('\t');
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, &code editor&);
ce-&installEventFilter( this );
bool MainWidget::eventFilter( QOject * target , QEvent * event )
&&&&&&&if( target == ce ){
&&&&&&&&&&&&&&if( event-&type() == QEvent::KeyPress ) {
&&&&&&&&&&&&&&&&&&&&&QKeyEvent *ke = (QKeyEvent *)
&&&&&&&&&&&&&&&&&&&&&if( ke-&key() == Key_Tab ){
ce-&insertAtCurrentPosition('\t');
&&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&}
4.给QAppliction对象安装事件过滤器
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个eventFilter().&在debug的时候,这个办法就非常有用,&也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. (&在QApplication::notify()&中,&是先调用qApp的过滤器,&再对事件进行分析,&以决定是否合并或丢弃)
5.继承QApplication类,并重载notify()函数
Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法.&通常来说事件过滤器更好用一些,&因为不需要去继承QApplication类.&而且可以给QApplication对象安装任意个数的事件过滤器,&相比之下, notify()函数只有一个.
http://www.cnblogs.com/bingcaihuang/archive//1909369.html
Views(...) Comments()通过鼠标事件过滤器捕获鼠标滑动状态以实现单一窗口内的多页面跳转
[问题点数:40分,结帖人vacancy14]
通过鼠标事件过滤器捕获鼠标滑动状态以实现单一窗口内的多页面跳转
[问题点数:40分,结帖人vacancy14]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
2010年12月 移动平台大版内专家分月排行榜第二2010年11月 移动平台大版内专家分月排行榜第二
2011年5月 移动平台大版内专家分月排行榜第三2011年4月 移动平台大版内专家分月排行榜第三2011年3月 移动平台大版内专家分月排行榜第三
匿名用户不能发表回复!|没有更多推荐了,
不良信息举报
举报内容:
QT基础(二)----鼠标、键盘事件处理机制、信息拦截机制
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!一、Qt中事件处理的方式
1、事件处理模式一
& & & & 首先是事件源产生事件,最后是事件处理器对这些事件进行处理。然而也许大家会问,
Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是每个事件都对应同一个事件处理器,在该事件处理器中对不同的事件进行分类处理,这样的弊端有两点:第一,导致该事件处理器过于臃肿复杂;第二,这样不便于扩展,当系统新增加事件类型或者是我们需要使用到自定义事件时,就不得不修改Qt的源码来达到目的。所以Qt设计者的做法是针对不同类型的事件提供不同的事件处理器与之对应。这里又有一个问题了,Qt中是怎么让不同类型事件与之对应的事件处理器相关联的呢?我们不难猜想在事件和事件处理器中间必定有一个桥梁。这个桥梁就是QObject::event()函数,该函数是虚函数,QObject的子类例如QWidget都实现了该函数。该函数的主要功能是进行事件的分发,也就是将不同类型的事件与之相对应的事件处理器相关联,该函数并不对事件进行处理,真正的事件处理是在事件处理器中进行的。
& & & & 例如:当QWidget产生QPaintEvent事件后,QWidget的event函数会将该事件分发给QWidget::paintEvent()事件处理器,这样该事件就得到处理了。
以上内容用一个图形表示就是:
2、事件处理模式二
& & & & 很多时候,我们只对某些特定的事件比较关心,例如:鼠标单击或者键盘按下等事件。其它的事件我们并不关心它是否发生,也无需对它们进行处理,这个时候最直接的想法就是将这些事件过滤掉,这样做既可以免去对它们进行处理,也可以避免它们对程序其它部分产生影响。因此,处理模式二中我们引入了事件过滤器这个概念。
& & & & 如果对象安装了事件过滤器,则事件在到达目标对象之前先被事件过滤器截获,进行一些处理之后再交给目标对象,该模式总结为一个图如下:
注意:这里需要区别对待,如果你是使用installEventFilter()函数给目标对象注册事件过滤器,那么该事件过滤器只对该目标对象有效,只有该对象的事件需要先传递给eventFilter()函数进行过滤,然后调用相应的事件处理器进行处理,非目标对象则不受影响。如果你是给程序中唯一的QApplication对象注册事件过滤器,那么该过滤器对程序中的每一个对象都有效,任何对象的事件都是先传给eventFilter()函数,然后再使用事件处理器进行处理。
3、事件处理模式三
& & & & Qt调用QApplicaton来发送一个事件。所以我们可以重新实现QApplication中的notify()函数来获取事件并进行处理,而且使用该函数获取事件的时间要早于事件过滤器获取事件的时间。但是使用事件过滤器较为简便,因为我们可以有多个事件过滤器,但是只能有一个notify()函数。用一个图来总结该模式就是:
二、Qt中事件处理的方法
& & & & 从以上三个处理模式我们可以看出,这是一个不断完善的过程,从3个模式的讨论中我们不难找到可以进行事件处理的地方,而这几个地方就是我们在编写程序的时候可以控制事件处理的地方。1、event()函数首先是控制事件分发的event()函数,我们可以改写该函数,改变事件的分发方式,这样就可以改变事件处理的结果。2、notify()函数实现该函数可以截获事件,并对事件加以处理,但是该方法很少用,这里不做介绍。3、事件过滤器实现自己的事件过滤器就可以改变事件处理的方法和结果,这个方法比较常用。4、事件处理器事件处理的最后一步,也是最重要的一步就是事件处理器,因为它才是真正进行事件处理的地方,我们可以改写以有的事件处理器,以此改变已有事件的处理方法和处理结果,我们也可以定义自己的事件类型和相应的事件处理器。
注意:以上四种方法中最常用的是后两者:事件过滤器和事件处理器。
补充内容:
1、事件的传递
& & & & 包括鼠标和键盘事件在内的很多事件都可以被传递。如果事件在到达目标对象之前没有被截获处理,或者已经传递给了它的目标对象但目标对象并没有进行处理,那么此时,目标对象的父对象将变成新的目标对象,整个事件处理的过程将重复进行,直到该事件被处理或者到达最顶层对象为止。
2、event实例解析
& & & &下面的代码是QWidget::event()函数的代码,从代码中可以看出event()函数确实只进行事件的分发而不负责事件的处理。由于函数代码过多,且都是一类型的用switch语句进行处理的,这里只贴出一部分代码:
bool&QWidget::event(QEvent&*event)&&
&&&&Q_D(QWidget);&&
&&&&if&(!isEnabled())&{&&
&&&&&&&&switch(event-&type())&{&&
&&&&&&&&case&QEvent::TabletPress:&&
&&&&&&&&case&QEvent::TabletRelease:&&
&&&&&&&&case&QEvent::TabletMove:&&
&&&&&&&&case&QEvent::MouseButtonPress:&&
&&&&&&&&case&QEvent::MouseButtonRelease:&&
&&&&&&&&case&QEvent::MouseButtonDblClick:&&
&&&&&&&&case&QEvent::MouseMove:&&
&&&&&&&&case&QEvent::TouchBegin:&&
&&&&&&&&case&QEvent::TouchUpdate:&&
&&&&&&&&case&QEvent::TouchEnd:&&
&&&&&&&&case&QEvent::ContextMenu:&&
#ifndef&QT_NO_WHEELEVENT&&
&&&&&&&&case&QEvent::Wheel:&&
&&&&&&&&&&&&return&&&
&&&&&&&&default:&&
&&&&&&&&&&&&&&
&&&&&&&&}&&
&&&&switch&(event-&type())&{&&
&&&&case&QEvent::MouseMove:&&
&&&&&&&&mouseMoveEvent((QMouseEvent*)event);&&
&&&&&&&&&&
&&&&case&QEvent::MouseButtonPress:&&
&&&&&&&&resetInputContext();&&
&&&&&&&&mousePressEvent((QMouseEvent*)event);&&
&&&&&&&&&&
&&&&case&QEvent::MouseButtonRelease:&&
&&&&&&&&mouseReleaseEvent((QMouseEvent*)event);&&
&&&&&&&&&&
&&&&case&QEvent::MouseButtonDblClick:&&
&&&&&&&&mouseDoubleClickEvent((QMouseEvent*)event);&&
&&&&&&&&&&
#ifndef&QT_NO_WHEELEVENT&&
&&&&case&QEvent::Wheel:&&
&&&&&&&&wheelEvent((QWheelEvent*)event);&&
&&&&&&&&&&
#ifndef&QT_NO_TABLETEVENT&&
&&&&case&QEvent::TabletMove:&&
&&&&case&QEvent::TabletPress:&&
&&&&case&QEvent::TabletRelease:&&
&&&&&&&&tabletEvent((QTabletEvent*)event);&&
&&&&&&&& &
& & 在上一篇中我们了解了Qt中事件处理的方式,也提到了最常用的就是使用事件处理器和事件过滤器这两种方法。在这一篇,我们就来看看事件处理器和事件过滤器是怎么使用的。
一、事件处理器使用实例
& & & &Qt中针对每一种常见的事件类型都提供了相应的事件处理器,我们如果想捕获某种类型的事件并进行自定义处理,那么只需要实现重写这些事件处理器就行,至于常见的时间类型和对应的事件处理器如下图:& & & & 在我的程序中,我使用到了鼠标滚轮事件,主要实现的就效果就是大家比较熟悉的:用一个控件显示图片,当滚动鼠标滚轮的时候可以调整图片显示的大小。& & & & 这里我要做的就是捕获该图片显示控件的鼠标滚轮事件,然后改写该控件的鼠标滚轮滚动事件处理器。& & & & 首先我们来看看鼠标滚轮事件以及相应的事件处理器是啥,查看上面的图即可知道:& & & & 在Qt帮助文档里面我们可以查看到如下语句“The event handler QWidget::wheelEvent() receives wheel events.”。也就是说最后事件处理器会调用wheelEvent()函数来处理该事件,因此我们需要的就是改写wheelEvent()这个函数。
第一步:在头文件中申明该函数:
第二步实现wheelEvent()函数(这里主要关注的是事件处理的框架,而不是具体的示例,因此不去过多讲解代码细节):
&span&style="font-size:16"&void&ImageWidget::wheelEvent(QWheelEvent&*event)&&
&&&&int&numDegrees&=&event-&delta();&&
&&&&int&num&=&numDegrees&/&120;&&
&&&&if(num&&&0)&&
&&&&&&&&num&=&0&-&&&
&&&&if&(event-&orientation()&==&Qt::Horizontal)&{&&
&&&&&&&&scale&*=&1.25;&&
&&&&&&&&resize(this-&scale&*&this-&size());&&
&&&&}&else&{&&
&&&&&&&&if(numDegrees&&&0)&&
&&&&&&&&{&&
&&&&&&&&&&&&
&&&&&&&&&&&&resize(num&*&0.75&*&this-&size());&&
&&&&&&&&}&&
&&&&&&&&else&if(numDegrees&&&0)&&
&&&&&&&&{&&
&&&&&&&&&&&&
&&&&&&&&&&&&resize(num&*&1.25&*&this-&size());&&
&&&&&&&&}&&
&&&&event-&accept();&&
}&/span&&&
& & & & 到这里这个功能就实现了,大家看看上面的头文件就知道这里还实现了其它类型事件的处理,其实都是一样的思路,找到欲处理的事件类型,找到对应的事件处理器,重写事件处理器中处理事件的方法即可。
二、事件过滤器使用实例
& & & & Qt事件模型中一项非常强大的功能就是一个QObject实例可以监视另一个QObject实例中的事件,实现方法是在目标对象中安装事件过滤器。这里我们接着上面的实例进行,为上面的图片浏览器增加一个功能:在我的程序中设置了一个自动播放的按键,点击按键后,在图片显示部件中就会显示一系列图片,就像动画播放许多幅图片一样,当在上面点击鼠标左键时,就停止动画播放而是停留在当前播放的图片;当我再点击鼠标右键的时候,又恢复为动画播放模式。& & & & 首先说一下主要的页面布局:我在一个QMainWindow中放置一个自定义的图片显示部件。对照上面的说明,我们很容易知道,实现该功能的方法就是在目标部件(自定义的图片显示部件)上注册事件过滤器,此时的事件过滤器就是我们所说的监视对象,完成这些步骤之后,当目标部件有事件产生后,首先会传递给监视对象(事件过滤器)进行处理而不是该事件对应的事件处理器。所以说我们可以截获事件进行处理。监视对象截获目标对象的事件后就会调用自己的eventFilter()函数处理这些事件。总结起来就两个步骤:第一:对目标对象调用installEventFilter()来注册监视对象(事件过滤器);第二:重写监视对象的eventFilter()函数处理目标对象的事件。我们就严格按照这两步走:首先使用installEventFilter()函数给目标对象注册事件监听器:
&span&style="font-size:16"&
imageWidget-&installEventFilter(this);&/span&&&
然后就是重写监视对象eventFilter()函数:
&span&style="font-size:16"&
bool&PMainWindow::eventFilter(QObject&*target,&QEvent&*event)&&
&&&&if(target&==&imageWidget)&&
&&&&&&&&qDebug("The&imageWidget&generate&the&event!");&&
&&&&&&&&if(event-&type()&==&QEvent::MouseButtonPress)&&
&&&&&&&&{&&
&&&&&&&&&&&&QMouseEvent&*mouseEvent&=&static_cast&QMouseEvent&*&(event);&&
&&&&&&&&&&&&if(mouseEvent-&buttons()&&&Qt::LeftButton)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&qDebug("The&Left&Button&Event!");&&
&&&&&&&&&&&&&&&&killTimer(timeId);&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&else&if(mouseEvent-&buttons()&&&Qt::RightButton)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&qDebug("The&Right&Button&Event!");&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&timeId&=&startTimer(3000);&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&return&&&
&&&&&&&&}&&
&&&&return&QMainWindow::eventFilter(target,&event);&&
}&/span& &
阅读(...) 评论() &QT父子窗口事件传递与事件过滤器
我的图书馆
QT父子窗口事件传递与事件过滤器
  处理监控系统的时候遇到问题,在MainWidget中创建多个子Widget的时候,原意是想鼠标点击先让MainWidget截获处理后再
分派给子Widget去处理,但调试后发现如果子Widget重新实现了事件方法,就直接处理掉事件了,没有进到MainWidget的处理方法中去,如
果子Widget没有accept或ignore该事件,则该事件就会被传递给其父亲,在子Widget存在accept或ignore事件的时候,想要
经过一下MainWidget的处理方法,就得用到事件处理器,因此网上找了一下,发现QT的事件处理器可以处理。
  QT将事件封装为QEvent实例以后,会呼叫QObject的event()方法,并且将QEvent实例传送给它,在某些情况下,希望在执行event()之前,先对一些事件进行处理或过滤,然后再决定是否呼叫event()方法,这时候可以使用事件过滤器。
  可以重新定义一个继承自QObject(或其子类)的类的eventFilter()方法,
bool FilterObject::eventFilter(QObject *object, QEvent *event)
  if(event-&type() == QEvent::KeyPress)
  {&& & & &
    QKeyEvent *keyEvent = static_cast&QKeyEvent *&(event);&& & & &
    if (keyEvent-&key() == Qt::Key_Tab)&
      // 处理Tab键 & & & & &&
      && & &&
eventFilter()的object参数表示事件发生的来源物件,eventFilter()若返回false,则安装该事件过滤器的对象的
event()会继续执行,若返回true,则安装事件过滤器的对象后event()方法就不会被执行,由此进行事件的拦截处理。给本对象安装事件过滤
this-&installEventFilter(this);
Qt事件的类型很多,&常见的qt的事件如下:
键盘事件:&按键按下和松开.
鼠标事件:&鼠标移动,鼠标按键的按下和松开.
拖放事件:&用鼠标进行拖放.
滚轮事件:&鼠标滚轮滚动.
绘屏事件:&重绘屏幕的某些部分.
定时事件:&定时器到时.
焦点事件:&键盘焦点移动.
进入和离开事件:&鼠标移入widget之内,或是移出.
移动事件: widget的位置改变.
大小改变事件: widget的大小改变.
显示和隐藏事件: widget显示和隐藏.
窗口事件:&窗口是否为当前窗口.
还有一些非常见的qt事件,比如socket事件,剪贴板事件,字体改变,布局改变等等.
Qt的事件和Qt中的signal不一样.&后者通常用来"使用"widget,&而前者用来"实现"
widget.&比如一个按钮,&我们使用这个按钮的时候,&我们只关心他clicked()的signal,&至于这个按钮如何接收处理鼠标事件,再发
射这个信号,我们是不用关心的.&但是如果我们要重载一个按钮的时候,我们就要面对event了.&比如我们可以改变它的行为,在鼠标按键按下的时候
(mouse press event)&就触发clicked()的signal而不是通常在释放的( mouse release
event)时候.
事件的产生
事件的两种来源:
&&&&&&&一种是系统产生的;通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等,&放入系统的消息队列中. Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.
&&&&&&&一种是由Qt应用程序程序自身产生的.程序产生事件有两种方式,&一种是调用
QApplication::postEvent().&例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()
函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理.&另
一种方式是调用sendEvent()函数.&这时候事件不会放入队列,&而是直接被派发和处理,
QWidget::repaint()函数用的就是这种方式.
事件的调度
两种调度方式,一种是同步的,&一种是异步.
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中一个独特的事件处理机制,&功能强大而且使用起来灵活方便.&通过它,&可以让一个对象侦听
拦截另外一个对象的事件.&事件过滤器是这样实现的:&在所有Qt对象的基类:
QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObjec
(qobjA)给另一个QObject (qobjB)安装了事件过滤器之后,
qobjB会把qobjA的指针保存在eventFilters中.&在qobjB处理事件之前,会先去检查eventFilters列表,&如果非
空,&就先调用列表中对象的eventFilter()函数.&一个对象可以给多个对象安装过滤器.&同样,&一个对象能同时被安装多个过滤器,&在事件
到达之后,&这些过滤器以安装次序的反序被调用.&事件过滤器函数( eventFilter()
)&返回值是bool型,&如果返回true,&则表示该事件已经被处理完毕,
Qt将直接返回,&进行下一事件的处理;&如果返回false,&事件将接着被送往剩下的事件过滤器或是目标对象进行处理.
Qt中,事件的派发是从QApplication::notify()&开始的,&因为QAppliction也是继承自QObject,&所以先
检查QAppliation对象,&如果有事件过滤器安装在qApp上,&先调用这些事件过滤器.&接下来
QApplication::notify()&会过滤或合并一些事件(比如失效widget的鼠标事件会被过滤掉,&而同一区域重复的绘图事件会被合
并).&之后,事件被送到reciver::event()&处理.
同样,&在reciver::event()中,&先检查有无事件过滤器安装在reciever上.&若有,&则调用之.&接下来,根据
QEvent的类型,&调用相应的特定事件处理函数.&一些常见的事件都有特定事件处理函数,&比如:mousePressEvent(),
focusOutEvent(),&&resizeEvent(), paintEvent(),
resizeEvent()等等.&在实际应用中,&经常需要重载这些特定事件处理函数在处理事件.&但对于那些不常见的事件,&是没有相对应的特定事件
处理函数的.&如果要处理这些事件,&就需要使用别的办法,&比如重载event()&函数,&或是安装事件过滤器.
事件的转发
&对于某些类别的事件,&如果在整个事件的派发过程结束后还没有被处理,&那么这个事件将会向上转发给它的父widget,&直到最顶层窗口.&如图所示,&事件最先发送给QCheckBox,&如果QCheckBox没有处理,&那么由QGroupBox接着处理,&如果QGroupBox没有处理,&再送到QDialog,&因为QDialog已经是最顶层widget,&所以如果QDialog不处理, QEvent将停止转发.
如何判断一个事件是否被处理了呢? Qt中和事件相关的函数通过两种方式相互通信. QApplication::notify(), QObject::eventFilter(), QObject::event()&通过返回bool值来表示是否已处理. “真”表示已经处理, “假”表示事件需要继续传递.&另一种是调用QEvent::ignore()&或&QEvent::accept()&对事件进行标识.&这种方式只用于event()&函数和特定事件处理函数之间的沟通.&而且只有用在某些类别事件上是有意义的,&这些事件就是上面提到的那些会被转发的事件,&包括:&鼠标,&滚轮,&按键等事件.
1.重载特定事件处理函数
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent()&这样的特定事件处理函数.&以按键事件为例,&一个典型的处理函数如下:
void imageView::keyPressEvent(QKeyEvent * event)
switch (event-&key()) {
case Key_Plus:
case Key_Minus:
zoomOut();
case Key_Left:
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 *)
if (keyEvent-&key() == Key_Tab) {
insertAtCurrentPosition('\t');
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, “code editor”);
ce-&installEventFilter( this );
bool MainWidget::eventFilter( QOject * target , QEvent * event )
&&&&&&&if( target == ce ){
&&&&&&&&&&&&&&if( event-&type() == QEvent::KeyPress ) {
&&&&&&&&&&&&&&&&&&&&&QKeyEvent *ke = (QKeyEvent *)
&&&&&&&&&&&&&&&&&&&&&if( ke-&key() == Key_Tab ){
ce-&insertAtCurrentPosition('\t');
&&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&}
4.给QAppliction对象安装事件过滤器
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个eventFilter().&在debug的时候,这个办法就非常有用,&也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. (&在QApplication::notify()&中,&是先调用qApp的过滤器,&再对事件进行分析,&以决定是否合并或丢弃)
5.继承QApplication类,并重载notify()函数
Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法.&通常来说事件过滤器更好用一些,&因为不需要去继承QApplication类.&而且可以给QApplication对象安装任意个数的事件过滤器,&相比之下, notify()函数只有一个.
TA的最新馆藏[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢

我要回帖

更多关于 鼠标一直闪烁怎么处理 的文章

 

随机推荐