QT程序设计编程进阶-事件.ppt

上传人:仙人指路1688 文档编号:2552895 上传时间:2023-02-20 格式:PPT 页数:37 大小:220.50KB
返回 下载 相关 举报
QT程序设计编程进阶-事件.ppt_第1页
第1页 / 共37页
QT程序设计编程进阶-事件.ppt_第2页
第2页 / 共37页
QT程序设计编程进阶-事件.ppt_第3页
第3页 / 共37页
QT程序设计编程进阶-事件.ppt_第4页
第4页 / 共37页
QT程序设计编程进阶-事件.ppt_第5页
第5页 / 共37页
点击查看更多>>
资源描述

《QT程序设计编程进阶-事件.ppt》由会员分享,可在线阅读,更多相关《QT程序设计编程进阶-事件.ppt(37页珍藏版)》请在三一办公上搜索。

1、QT程序设计进阶-事件,www.gec-edu.org,www.gec-edu.org,QT的事件机制,Qt事件 Qt程序是事件驱动的,程序的每个动作都是由幕后某个事件所触发.Qt事件的类型很多,常见的qt的事件如下:键盘事件:按键按下和松开.鼠标事件:鼠标移动,鼠标按键的按下和松开.拖放事件:用鼠标进行拖放.滚轮事件:鼠标滚轮滚动.绘屏事件:重绘屏幕的某些部分.定时事件:定时器到时.焦点事件:键盘焦点移动.进入和离开事件:鼠标移入widget之内,或是移出.移动事件:widget的位置改变.大小改变事件:widget的大小改变.显示和隐藏事件:widget显示和隐藏.窗口事件:窗口是否为当前

2、窗口.还有一些非常见的qt事件,比如socket事件,剪贴板事件,字体改变,布局改变等等.,www.gec-edu.org,QT的事件机制,Qt 的事件和Qt中的signal不一样.后者通常用来使用widget,而前者用来实现 widget.比如一个按钮,我们使用这个按钮的时候,我们只关心他clicked()的signal,至于这个按钮如何接收处理鼠标事件,再发射这个信号,我们是不用关心的.但是如果我们要重载一个按钮的时候,我们就要面对event了.比如我们可以改变它的行为,在鼠标按键按下的时候(mouse press event)就触发clicked()的signal而不是通常在释放的(mo

3、use release event)时候.,www.gec-edu.org,QT的事件机制,事件起源:基于事件如何被产生与分发,可以把事件分为三类:*Spontaneous 事件*Posted 事件*Sent 事件,www.gec-edu.org,QT的事件机制,Spontaneous 事件,由窗口系统产生,它们被放到系统队列中,通过事件循环逐个处理。本类事件通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等,放入系统的消息队列中.Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.Posted 事件,由Qt或是应用程序产生,它们被Qt组成队列,再通过事件

4、循环处理。调用QApplication:postEvent()来产生一个posted类型事件.例如:QWidget:update()函数当需要重新绘制屏幕时,程序调用update()函数其实现的原理是new出一个paintEvent,调用 QApplication:postEvent(),将其放入Qt的消息队列中,等待依次被处理.,www.gec-edu.org,QT的事件机制,Sent 事件由Qt或是应用程序产生,但它们被直接发送到目标对象。调用QApplication:sendEvent()函数来产生一个sent类型事件.sent 类型事件不会放入队列,而是直接被派发和处理,QWidget

5、:repaint()函数用的就是这种方式.,www.gec-edu.org,QT的事件机制,当我们在main()函数的末尾调用QApplication:exec()时,程序进入了Qt的事件循环事件循环如下面所示:while(!exit_was_called)while(!posted_event_queue_is_empty)process_next_posted_event();while(!spontaneous_event_queue_is_empty)process_next_spontaneous_event();while(!posted_event_queue_is_empty)

6、process_next_posted_event();,www.gec-edu.org,QT的事件机制,事件循环的处理流程:先处理Qt事件队列中的posted事件,直至为空 再处理系统消息队列中的spontaneous消息,直至为空 在处理系统消息的时候会产生新的Qt posted事件,需要对其再次进行处理 不通过事件循环sendEvent的事件派发不通过事件循环。QApplication:sendEvent()是通过调用QApplication:notify(),直接进入了事件的派发和处理环节。,www.gec-edu.org,QT的事件机制,Notify调用QApplication:se

7、ndEvent的时候,消息会立即被处理,是同步的.实际上QApplication:sendEvent()是通过调用QApplication:notify(),直接进入了事件的派发和处理环节.所有的事件都最终通过 notify 派发到相应的对象中。bool QApplication:notify(QObject*receiver,QEvent*event)它是通过调用receiver-event(event)来实现的。目标接受对象的event方法会自动接受notify传来的event事件event()会返回一个布尔值,来告诉调用者是否事件被accept或ignore,(true表示accept)

8、,从event()返回的布尔值却是用来与QApplication:notify()通讯的。,www.gec-edu.org,QT的事件机制,event()函数的处理如下所示:bool QWidget:event(QEvent*event)switch(e-type()case QEvent:KeyPress:keyPressEvent(QKeyEvent*)event);if(!(QKeyEvent*)event)-isAccepted()return false;break;case QEvent:KeyRelease:keyReleaseEvent(QKeyEvent*)event);if

9、(!(QKeyEvent*)event)-isAccepted()return false;break;.return true;,www.gec-edu.org,QT的事件机制,Close事件有点不同,调用QCloseEvent:ignore()取消了关闭操作,而accept()告诉Qt继续执行正常的关闭操作。为了避免混乱,最好是在closeEvent()的新实现中明确地进行accept()与ignore()的调用:、void MainWindow:closeEvent(QCloseEvent*event)if(userReallyWantsToQuit()event-accept();el

10、se event-ignore();,www.gec-edu.org,keyPressEvent,在空白窗体页面,重载当前窗体类的keyPressEvent方法,实现按键事件的响应。步骤一:添加头文件在form.cpp中填加void Form1:keyPressEvent(QKeyEvent*k)并实现根据不同的键值,执行不同的动作。步骤二:添加头文件在form.h 中为窗体类form1添加 void keyPressEvent(QKeyEvent*k)声明;步骤三:重新编译工程并运行测试。,www.gec-edu.org,keyPressEvent,void Form1:keyPressEv

11、ent(QKeyEvent*k)if(k-key()=Key_Left)qDebug(Leftn);.else if(k-key()=Key_Right)qDebug(Rightn);.else QWidget:keyPressEvent(k);,www.gec-edu.org,keyPressEvent,在具备子控件的复杂窗体中,重载当前窗体类的keyPressEvent方法,实现按键事件的响应。步骤一:添加头文件在form.cpp中填加void Form1:keyPressEvent(QKeyEvent*k)并实现根据不同的键值,执行不同的动作。步骤二:添加头文件在form.h 中为窗体类

12、form1添加 void keyPressEvent(QKeyEvent*k)声明;步骤三:在form.cpp中,消除子控件的焦点策略,使能方向及Tab按键功能。步骤四:重新编译工程并运行测试。,www.gec-edu.org,keyPressEvent,例如:pushButton1=new QPushButton(this,pushButton1);pushButton1-setGeometry(QRect(200,150,111,41);pushButton1-setFocusPolicy(QWidget:NoFocus);void QWidget:setFocusPolicy(Focus

13、Policy)设置这个窗口部件接收键盘焦点的方式。“focusPolicy”属性保存的是窗口部件接收键盘焦点的策略。如果窗口部件通过tab来接收键盘焦点,这个策略就是QWidget:TabFocus;如果窗口部件通过点击来接收键盘焦点,这个策略就是QWidget:ClickFocus;如果窗口部件上述两种方式都使用,是QWidget:StrongFocus;如果它不接收焦点(QWidget的默认值),是QWidget:NoFocus。,www.gec-edu.org,event,重载当前窗体类的event方法,实现针对性事件的处理与过滤效果。步骤一:在form.cpp中填加bool Form1

14、:event(QEvent*event)并实现根据不同的键值,执行不同的动作。步骤二:在form.h 中为窗体类form1添加 bool event(QEvent*event)声明;步骤三:重新编译工程并运行测试。,www.gec-edu.org,event,bool Form1:event(QEvent*event)if(event-type()=QEvent:KeyPress)QKeyEvent*keyEvent=(QKeyEvent*)event;if(keyEvent-key()=Key_A)qDebug(-cut the Key_A-n);return true;return QWi

15、dget:event(event);,www.gec-edu.org,eventFilter,Qt事件模型一个真正强大的特色是一个QObject 的实例能够管理另一个QObject 实例的事件。一个CustomerDialog的小部件。CustomerDialog 包含一系列QLineEdit.现在,我们想用空格键来代替Tab,使焦点在这些QLineEdit间切换。一个解决的方法是子类化QLineEdit,重新实现keyPressEvent(),并在keyPressEvent()里调用focusNextChild()。像下面这样:void MyLineEdit:keyPressEvent(QK

16、eyEvent*event)if(event-key()=Qt:Key_Space)focusNextChild();else QLineEdit:keyPressEvent(event);,www.gec-edu.org,eventFilter,上述做法有一个缺点。如果CustomerDialog里有很多不同的控件(比如QComboBox,QEdit,QSpinBox),我们就必须子类化这么多控件。这是一个烦琐的任务。一个更好的解决办法是:让CustomerDialog去管理他的子部件的按键事件,实现要求的行为。我们可以使用事件过滤器。一个事件过滤器的安装需要下面2个步骤:1,调用insta

17、llEventFilter()注册需要管理的对象。2,在eventFilter()里处理需要管理的对象的事件。一般,推荐在CustomerDialog的构造函数中注册被管理的对象。像下面这样:CustomerInfoDialog:CustomerInfoDialog(QWidget*parent):QDialog(parent).firstNameEdit-installEventFilter(this);lastNameEdit-installEventFilter(this);cityEdit-installEventFilter(this);phoneNumberEdit-install

18、EventFilter(this);一旦,事件管理器被注册,发送到firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit的事件将首先发送到eventFilter()。,www.gec-edu.org,eventFilter,下面是一个 eventFilter()函数的实现:bool CustomerInfoDialog:eventFilter(QObject*target,QEvent*event)if(target=firstNameEdit|target=lastNameEdit|target=cityEdit|target=phoneNum

19、berEdit)if(event-type()=QEvent:KeyPress)QKeyEvent*keyEvent=static_cast(event);if(keyEvent-key()=Qt:Key_Space)focusNextChild();return true;return QDialog:eventFilter(target,event);,www.gec-edu.org,eventFilter,在上面的函数中,我们首先检查目标部件是否是 firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit。接着,我们判断事件是否是按键事件。如

20、果事件是按键事件,我们把事件转换为QKeyEvent。接着,我们判断是否按下了空格键,如果是,我们调用focusNextChild(),把焦点传递给下一个控件。然后,返回,true通知Qt,我们已经处理了该事件。如果返回false的话,Qt继续将该事件发送给目标控件,结果是一个空格被插入到QLineEdit中。如果目标控件不是 QLineEdit,或者按键不是空格键,我们将把事件传递给基类的eventFilter()函数。,www.gec-edu.org,eventFilter,Qt提供5个级别的事件处理和过滤:1,重新实现事件函数。比如:mousePressEvent(),keyPress-

21、Event(),paintEvent()。这是最常规的事件处理方法。2,重新实现QObject:event().这一般用在Qt没有提供该事件的处理函数时。也就是,我们增加新的事件时。3,安装事件过滤器 4,在 QApplication 上安装事件过滤器。QApplication 上的事件过滤器将捕获应用程序的所有事件,而且第一个获得该事件。也就是说事件在发送给其它任何一个event filter之前发送给QApplication的event filter。5,重新实现QApplication 的 notify()方法.Qt使用 notify()来分发事件。要想在任何事件处理器捕获事件之前捕获事

22、件,唯一的方法就是重新实现QApplication 的 notify()方法。,www.gec-edu.org,eventFilter,在创建了过滤器之后,下面要做的是安装这个过滤器。安装过滤器需要调用installEventFilter()函数。这个函数的签名如下:void QObject:installEventFilter(QObject*filterObj)这个函数是QObject的一个函数,因此可以安装到任何QObject的子类,并不仅仅是UI组件。这个函数接收一个QObject对象,调用了这个函数安装事件过滤器的组件会调用filterObj定义的eventFilter()函数。例如

23、,textField-installEventFilter(obj),则如果有事件发送到textField组件是,会先调用obj-eventFilter()函数,然后才会调用textField-event()。也可以把事件过滤器安装到QApplication上面,这样就可以过滤所有的事件,已获得更大的控制权。不过,这样做的后果就是会降低事件分发的效率。如果一个组件安装了多个过滤器,则最后一个安装的会最先调用,类似于堆栈的行为。,www.gec-edu.org,eventFilter,pushButton2=new QPushButton(this,pushButton2);pushButton

24、2-setGeometry(QRect(200,160,111,31);pushButton2-installEventFilter(this);bool Form1:eventFilter(QObject*o,QEvent*e)if(pushButton2=o)if(e-type()=QEvent:KeyPress)QKeyEvent*k=(QKeyEvent*)e;qDebug(eat key press%d,k-key();return TRUE;,www.gec-edu.org,eventFilter,if(e-type()=QEvent:MouseButtonPress)QMouse

25、Event*k=(QMouseEvent*)e;qDebug(eat Mouse press);return TRUE;else return FALSE;else return QWidget:eventFilter(o,e);,www.gec-edu.org,eventFilter,bool Form1:event(QEvent*event)if(event-type()=QEvent:KeyPress)QKeyEvent*keyEvent=(QKeyEvent*)event;if(keyEvent-key()=Key_A)qDebug(-cut the Key_A-n);return t

26、rue;return QWidget:event(event);,www.gec-edu.org,QT的事件机制,事件的产生QT应用程序可以产生自定义的事件,或是预定义类型,或是自定义类型。这可以通过创建QEvent类或它的子类的实例,并且调用QApplication:postEvent()或QApplication:sendEvent()来实现。这两个函数需要一个 QObject*与一个QEvent*作为参数,假如你调用postEvent(),你必须用 new 操作符来创建事件对象,Qt会它被处理后帮你删除它。假如你用sendEvent(),你应该在栈上来创建事件。,www.gec-edu.

27、org,QT的事件机制,下面举两个例子:一是posting 事件:QApplication:postEvent(mainWin,new QKeyEvent(QEvent:KeyPress,Key_X,X,0,X);二是sending 事件:QKeyEvent event(QEvent:KeyPress,Key_X,X,0,X);QApplication:sendEvent(mainWin,Qt应用程序很少直接调用postEvent()或是sendEvnet(),因为大多数事件会在必要时被Qt或是窗口系统自动产生。在大多数的情况下,当你想发送一个事件时,Qt已经为你准备好了一个更高级的函数来为你

28、服务。(例如update()与repaint()。为了提高qt程序的自定义特性,可以显式得采用程序实现事件的发送。,www.gec-edu.org,QT的事件机制,重绘事件 paintEvent()当窗口被其他窗口覆盖后,再次重新显示时,系统将产生 spontaneous 事件来请求重绘,事件循环最终从事件队列中捡选这个事件并把它分发到那个需要重画的widget。当我们调用 QWidget:update()时,产生的是 Posted 重绘事件 当我们调用 QWidget:repaint()时,产生的是 Sent 重绘事件,www.gec-edu.org,QT的事件机制,posting 相对于s

29、ending的一个优势是,它给了Qt一个压缩(compress)事件的机会。假如你在一个widget上连续地调用update()十次,因update()而产生的这十个事件,将会自动地被合并为一个单独的事件,但是QPaintEvents事件附带的区域信息也合并了。可压缩的事件类型包括:paint,move,resize,layout hint,language change。最后要注意,可以在任何时候调用QApplication:sendPostedEvent(),强制Qt产生一个对象的posted事件。,www.gec-edu.org,QT的事件机制,Qt 系统还提供了一个 QCustomEv

30、ent 类,用于用户自定义事件,这些自定义事件可以利用 QThread:postEvent()或者QApplication:postEvent()被发给各种控件或其他 QObject 实例。QWidget 类的子类可以通过 QWidget:customEvent()事件处理函数方便地接收到这些自定义的事件。需要注意的是:QCustomEvent 对象在创建时都带有一个类型标识 id 以定义事件类型,为了避免与 Qt 系统定义的事件类型冲突,该 id 值应该大于枚举类型 QEvent:Type 中给出的 User 值。,www.gec-edu.org,QT的事件机制,演示如何post一个定制事件

31、的代码片段:const QEvent:Type MyEvent=(QEvent:Type)1234;.QApplication:postEvent(mainwin,new QCustomEvent(MyEvent);事件必须是QCustomEvent类型(或子类)的。构造函数的参数是事件的类型,1000以下被Qt保留。其他可被程序使用。为处理定制事件类型,要重新实现customEvent()函数:,www.gec-edu.org,QT的事件机制,void MyWin:customEvent(QCustomEvent*event)if(event-type()=MyEvent)myEvent()

32、;else Qwidget:customEvent(event);QcustomEvent类有一个void*的成员,可用于特定的目的。你也可以子类化QCustomEvent,加上别的成员。,www.gec-edu.org,QT的事件机制,一些事件类型可以被传递。这意味着假如目标对象不处理一个事件,Qt会试着寻找另外的事件接收者。用新的目标来调用QApplication:notify()。举例来讲,key事件是传递的,假如拥有焦点的Widget不处理特定键,Qt会分发相同的事件给父widget,然后是父亲的父亲,直到最顶层widget。可被传递的事件可以“接收”或是“忽略”这个事件。假如事件被处

33、理,这个事件将不会再被传递。否则Qt会试着查找另外的事件接收者。大部分qt对象对事件的处理缺省情况下是“接收”,在QWidget中的缺省实现是调用“忽略”,假如你希望接收事件,你需要做的是重新实现事件handler,避免调用QWidget的实现。假如你想“忽略”事件,只需简单地传递它到QWidget的实现。,www.gec-edu.org,QT的事件机制,下面的代码演示了这一点:void MyWidget:keyPressEvent(QKeyEvent*event)if(event-key()=Key_Escape)doEscape();else QWidget:keyPressEvent(e

34、vent);在上面的例子里,假如用户按了ESC键,我们会调用doEscape()并且事件被“接收”了(这是缺省的情况),事件不会被传递到父widget,假如用户按了别的键,则调用QWidget的缺省实现。,www.gec-edu.org,QT的事件机制,void QWidget:keyPressEvent(QKeyEvent*event)event-ignore();此处调用ignore(),事件会被传递到父widget中去。以上假设基类都是QWidget,然而,同样的规则也可以应用到别的层次中,只要用其他基类代替QWidget即可。举例来说:void MyLineEdit:keyPressEvent(QKeyEvent*event)if(event-key()=Key_SysReq)doSystemRequest();else QLineEdit:keyPressEvent(event);,www.gec-edu.org,Thank You!,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 建筑/施工/环境 > 项目建议


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号