QT程序设计编程进阶事件_第1页
QT程序设计编程进阶事件_第2页
QT程序设计编程进阶事件_第3页
QT程序设计编程进阶事件_第4页
QT程序设计编程进阶事件_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

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

3、ress event) 就触发clicked()的signal而不是通常在释放的( mouse release event)时候.qt的事件机制的事件机制v 事件起源:事件起源:v 基于事件如何被产生与分发,可以把事件分为三类:基于事件如何被产生与分发,可以把事件分为三类:v * spontaneous 事件事件v * posted 事件事件v * sent 事件事件qt的事件机制的事件机制v spontaneous 事件事件,由窗口系统产生,它们被放到系统队列中,通过事件由窗口系统产生,它们被放到系统队列中,通过事件循环逐个处理。循

4、环逐个处理。v 本类事件通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等, 放入系统的消息队列中. qt事件循环的时候读取这些事件,转化为qevent,再依次处理.v posted 事件,由事件,由qt或是应用程序产生,它们被或是应用程序产生,它们被qt组成队列,再通过事件组成队列,再通过事件循环处理。循环处理。v 调用qapplication:postevent()来产生一个posted类型事件. v 例如:qwidget:update()函数v 当需要重新绘制屏幕时,程序调用update()函数v 其实现的原理是new出一个paintevent,调用 qappl

5、ication:postevent(),将其放入qt的消息队列中,等待依次被处理. qt的事件机制的事件机制v sent 事件事件v 由由qt或是应用程序产生,但它们被直接发送到目标对象。或是应用程序产生,但它们被直接发送到目标对象。v 调用qapplication:sendevent()函数来产生一个sent类型事件. v sent 类型事件不会放入队列, 而是直接被派发和处理, qwidget:repaint()函数用的就是这种方式.qt的事件机制的事件机制当我们在main()函数的末尾调用qapplication:exec()时

6、,程序进入了qt的事件循环v 事件循环如下面所示:v while (!exit_was_called)v v while(!posted_event_queue_is_empty)v v process_next_posted_event();v v while(!spontaneous_event_queue_is_empty)v v process_next_spontaneous_event();v v while(!posted_event_queue_is_empty)v v process_next_posted_event();v v qt的事件机制

7、的事件机制v 事件循环的处理流程:v 先处理qt事件队列中的posted事件,直至为空 v 再处理系统消息队列中的spontaneous消息,直至为空 v 在处理系统消息的时候会产生新的qt posted事件,需要对其再次进行处理 v 不通过事件循环v sendevent的事件派发不通过事件循环。qapplication:sendevent()是通过调用qapplication:notify(),直接进入了事件的派发和处理环节。qt的事件机制的事件机制v notifyv 调用qapplication:sendevent的时候, 消息会立即被处理,是同步的. 实际上

8、qapplication:sendevent()是通过调用qapplication:notify(), 直接进入了事件的派发和处理环节.所有的事件都最终通过 notify 派发到相应的对象中。v bool qapplication:notify ( qobject * receiver, qevent * event ) v 它是通过调用receiver-event(event) 来实现的。v 目标接受对象的event方法会自动接受notify传来的event事件v event() 会返回一个布尔值,来告诉调用者是否事件被accept或ignore,v (true表示accept),从even

9、t()返回的布尔值却是用来与qapplication:notify()通讯的。qt的事件机制的事件机制v event()函数的处理如下所示:v bool qwidget:event(qevent *event)v v switch (e-type() v case qevent:keypress:v keypressevent(qkeyevent *)event);v if (!(qkeyevent *)event)-isaccepted()v return false;v break;v case qevent:keyrelease:v keyreleaseev

10、ent(qkeyevent *)event);v if (!(qkeyevent *)event)-isaccepted()v return false;v break;v .v v return true;v qt的事件机制的事件机制v close事件有点不同,调用qcloseevent:ignore()取消了关闭操作,而accept()告诉qt继续执行正常的关闭操作。为了避免混乱,最好是在closeevent()的新实现中明确地进行accept()与ignore()的调用:、v void mainwindow:closeevent(qcloseevent *e

11、vent)v v if (userreallywantstoquit() v event-accept();v else v event-ignore();v v keypresseventv 在空白窗体页面,重载当前窗体类的在空白窗体页面,重载当前窗体类的keypressevent方法,实现按键事件方法,实现按键事件的响应。的响应。v 步骤一:v 添加头文件v 在form.cpp中填加void form1:keypressevent(qkeyevent *k )v 并实现根据不同的键值,执行不同的动作。v 步骤二:v 添加头文件v 在form.h 中为窗体类fo

12、rm1添加 void keypressevent(qkeyevent *k )声明;v 步骤三:v 重新编译工程并运行测试。keypresseventvvoid form1:keypressevent( qkeyevent *k )vv if(k-key() = key_left)v v qdebug(leftn);v .v v else if(k-key() = key_right)v v qdebug(rightn);v .v v else qwidget:keypressevent(k);keypresseventv在具备子控

13、件的复杂窗体中,重载当前窗体类的在具备子控件的复杂窗体中,重载当前窗体类的keypressevent方法,实现按键事方法,实现按键事件的响应。件的响应。v步骤一:v添加头文件v在form.cpp中填加void form1:keypressevent(qkeyevent *k )v并实现根据不同的键值,执行不同的动作。v步骤二:v 添加头文件v在form.h 中为窗体类form1添加 void keypressevent(qkeyevent *k )声明;v步骤三:v在form.cpp中,消除子控件的焦点策略,使能方向及tab按键功能。v步骤四:v重新编译工程并运行测试。www.gec-edu.

14、orgkeypresseventv 例如:v pushbutton1 = new qpushbutton( this, pushbutton1 );v pushbutton1-setgeometry( qrect( 200, 150, 111, 41 ) );v pushbutton1-setfocuspolicy(qwidget:nofocus);v void qwidget:setfocuspolicy ( focuspolicy ) v 设置这个窗口部件接收键盘焦点的方式。v “focuspolicy”属性保存的是窗口部件接收键盘焦点的策略。 v如果窗口部件通过tab来接收键盘焦点,这个

15、策略就是qwidget:tabfocus;v如果窗口部件通过点击来接收键盘焦点,这个策略就是qwidget:clickfocus;v如果窗口部件上述两种方式都使用,是qwidget:strongfocus;v如果它不接收焦点(qwidget的默认值),是qwidget:nofeventv 重载当前窗体类的重载当前窗体类的event方法,实现针对性事件的处理与过滤效果。方法,实现针对性事件的处理与过滤效果。v 步骤一:v 在form.cpp中填加bool form1:event(qevent *event)v 并实现根据不同的键值,执行不同的动作。v 步骤

16、二:v 在form.h 中为窗体类form1添加 bool event(qevent *event)声明;v 步骤三:v 重新编译工程并运行测试。eventv bool form1:event(qevent * event)v v if (event-type() = qevent:keypress)v v qkeyevent *keyevent = (qkeyevent *) event;v if (keyevent-key() = key_a)v v qdebug(-cut the key_a-n);v return true;v v v return qwi

17、dget:event(event);v eventfilterv qt事件模型一个真正强大的特色是一个qobject 的实例能够管理另一个qobject 实例的事件。 v 一个customerdialog的小部件。customerdialog 包含一系列qlineedit. 现在,我们想用空格键来代替tab,使焦点在这些qlineedit间切换。 v 一个解决的方法是子类化qlineedit,重新实现keypressevent(),并在keypressevent()里调用focusnextchild()。像下面这样: v void mylineedit:keypr

18、essevent(qkeyevent *event) v v if (event-key() = qt:key_space) v focusnextchild(); v else v qlineedit:keypressevent(event); v v eventfilterv上述做法有一个缺点。如果customerdialog里有很多不同的控件(比如qcombobox,qedit,qspinbox),我们就必须子类化这么多控件。这是一个烦琐的任务。 v一个更好的解决办法是: 让customerdialog去管理他的子部件的按键事件,实现要求的行为。我们可以使用

19、事件过滤器。 v一个事件过滤器的安装需要下面2个步骤: v1, 调用installeventfilter()注册需要管理的对象。 v2,在eventfilter() 里处理需要管理的对象的事件。 v一般,推荐在customerdialog的构造函数中注册被管理的对象。像下面这样: vcustomerinfodialog:customerinfodialog(qwidget *parent) : qdialog(parent)v . v firstnameedit-installeventfilter(this);v lastnameedit-installeventfilter(this);v

20、 cityedit-installeventfilter(this);v phonenumberedit-installeventfilter(this);v v一旦,事件管理器被注册,发送到firstnameedit,lastnameedit,cityedit,phonenumberedit的事件将首先发送到eventfilter()。 eventfilterv下面是一个下面是一个 eventfilter()函数的实现:函数的实现: vbool customerinfodialog:eventfilter(qobject *target, qevent *eve

21、nt) v v if (target = firstnameedit | target = lastnameedit v | target = cityedit | target = phonenumberedit) v if (event-type() = qevent:keypress) v qkeyevent *keyevent = static_cast(event); v if (keyevent-key() = qt:key_space) v focusnextchild(); v return true; v v v v return qdialog:eventfilter(ta

22、rget, event); v eventfilterv 在上面的函数中,我们首先检查目标部件是否是 firstnameedit,lastnameedit,cityedit,phonenumberedit。接着,我们判断事件是否是按键事件。如果事件是按键事件,我们把事件转换为qkeyevent。接着,我们判断是否按下了空格键,如果是,我们调用focusnextchild(),把焦点传递给下一个控件。然后,返回,true通知qt,我们已经处理了该事件。 v 如果返回false的话,qt继续将该事件发送给目标控件,结果是一个空格被插入到qlineedit中。 v 如果

23、目标控件不是 qlineedit,或者按键不是空格键,我们将把事件传递给基类的eventfilter()函数。eventfiltervqt提供提供5个级别的事件处理和过滤:个级别的事件处理和过滤: v1,重新实现事件函数。,重新实现事件函数。 比如:比如: mousepressevent(), keypress-event(), paintevent() 。 这是最常规的事件处理方法。这是最常规的事件处理方法。v2,重新实现,重新实现qobject:event(). v 这一般用在这一般用在qt没有提供该事件的处理函数时。也就是,我们增加新的事件时。没有提供该事件

24、的处理函数时。也就是,我们增加新的事件时。v v3,安装事件过滤器,安装事件过滤器 v4,在,在 qapplication 上安装事件过滤器。上安装事件过滤器。 v qapplication 上的事件过滤器将捕获应用程序的所有事件,而且第一个获得该事上的事件过滤器将捕获应用程序的所有事件,而且第一个获得该事件。也就是说事件在发送给其它任何一个件。也就是说事件在发送给其它任何一个event filter之前发送给之前发送给qapplication的的event filter。 v5,重新实现,重新实现qapplication 的的 notify()方法方法. vqt使用使用 notify()来分

25、发事件。要想在任何事件处理器捕获事件之前捕获事件,唯一来分发事件。要想在任何事件处理器捕获事件之前捕获事件,唯一的方法就是重新实现的方法就是重新实现qapplication 的的 notify()方法。方法。 eventfilterv在创建了过滤器之后,下面要做的是安装这个过滤器。安装过滤器需要调用在创建了过滤器之后,下面要做的是安装这个过滤器。安装过滤器需要调用installeventfilter()函数。这个函数的签名如下:函数。这个函数的签名如下:vvoid qobject:installeventfilter ( qobject * filterobj )

26、 v这个函数是这个函数是qobject的一个函数,因此可以安装到任何的一个函数,因此可以安装到任何qobject的子类,并不仅仅的子类,并不仅仅是是ui组件。这个函数接收一个组件。这个函数接收一个qobject对象,调用了这个函数安装事件过滤器的组对象,调用了这个函数安装事件过滤器的组件会调用件会调用filterobj定义的定义的eventfilter()函数。函数。v例如,例如,textfield-installeventfilter(obj),则如果有事件发送到,则如果有事件发送到textfield组组件是,会先调用件是,会先调用obj-eventfilter()函数,然后才会调用函数,然

27、后才会调用textfield-event()。v也可以把事件过滤器安装到也可以把事件过滤器安装到qapplication上面,这样就可以过滤所有的事件,已获上面,这样就可以过滤所有的事件,已获得更大的控制权。不过,这样做的后果就是会降低事件分发的效率。得更大的控制权。不过,这样做的后果就是会降低事件分发的效率。v如果一个组件安装了多个过滤器,则最后一个安装的会最先调用,类似于堆栈的行为。如果一个组件安装了多个过滤器,则最后一个安装的会最先调用,类似于堆栈的行为。eventfilterv pushbutton2 = new qpushbutton( this, pu

28、shbutton2 );v pushbutton2-setgeometry( qrect( 200, 160, 111, 31 ) );v pushbutton2-installeventfilter( this ); v bool form1:eventfilter( qobject *o, qevent *e )v v if( pushbutton2=o )v v if ( e-type() = qevent:keypress )v v qkeyevent *k = (qkeyevent *)e;v qdebug( eat key press %d, k-key() );v return

29、true; v eventfilterv if ( e-type() = qevent:mousebuttonpress )v v qmouseevent *k = (qmouseevent *)e;v qdebug( eat mouse press );v return true; v v else v return false;v v v elsev return qwidget:eventfilter( o, e ); eventfilterv bool form1:event(qevent * event)v v if (e

30、vent-type() = qevent:keypress)v v qkeyevent *keyevent = (qkeyevent *) event;v if (keyevent-key() = key_a)v v qdebug(-cut the key_a-n);v return true;v v v return qwidget:event(event);v qt的事件机制的事件机制v 事件的产生v qt应用程序可以产生自定义的事件,或是预定义类型,或是自定义类型。 这可以通过创建qevent类或它的子类的实例,并且调用qapplication:postev

31、ent()或qapplication:sendevent()来实现。v 这两个函数需要一个 qobject* 与一个qevent * 作为参数,假如你调用postevent(),你必须用 new 操作符来创建事件对象,qt会它被处理后帮你删除它。v 假如你用sendevent(), 你应该在栈上来创建事件。qt的事件机制的事件机制v 下面举两个例子:v 一是posting 事件:v qapplication:postevent(mainwin, new qkeyevent(qevent:keypress,key_x,x,0,x);v 二是sending 事件:v

32、qkeyevent event(qevent:keypress, key_x, x, 0,x);v qapplication:sendevent(mainwin, &event);v qt应用程序很少直接调用postevent()或是sendevnet(),因为大多数事件会在必要时被qt或是窗口系统自动产生。在大多数的情况下,当你想发送一个事件时,qt已经为你准备好了一个更高级的函数来为你服务。(例如update()与repaint()。v 为了提高qt程序的自定义特性,可以显式得采用程序实现事件的发送。qt的事件机制的事件机制v 重绘事件 paintev

33、ent()v 当窗口被其他窗口覆盖后,再次重新显示时,系统将产生 spontaneous 事件来请求重绘,事件循环最终从事件队列中捡选这个事件并把它分发到那个需要重画的widget。 v 当我们调用 qwidget:update() 时,产生的是 posted 重绘事件 v 当我们调用 qwidget:repaint() 时,产生的是 sent 重绘事件 qt的事件机制的事件机制v posting 相对于sending的一个优势是,它给了qt一个压缩(compress)事件的机会。假如你在一个widget上连续地调用update() 十次,因update()而产生

34、的这十个事件,将会自动地被合并为一个单独的事件,但是qpaintevents事件附带的区域信息也合并了。v 可压缩的事件类型包括:paint,move,resize,layout hint,language change。v 最后要注意,可以在任何时候调用qapplication:sendpostedevent(),强制qt产生一个对象的posted事件。qt的事件机制的事件机制v qt 系统还提供了一个 qcustomevent 类,用于用户自定义事件,这些自定义事件可以利用 qthread:postevent() 或者qapplication:posteven

35、t() 被发给各种控件或其他 qobject 实例。v qwidget 类的子类可以通过 qwidget:customevent() 事件处理函数方便地接收到这些自定义的事件。v 需要注意的是:qcustomevent 对象在创建时都带有一个类型标识 id 以定义事件类型,为了避免与 qt 系统定义的事件类型冲突,该 id 值应该大于枚举类型 qevent:type 中给出的 user 值。 qt的事件机制的事件机制v 演示如何post一个定制事件的代码片段:v const qevent:type myevent = (qevent:type)1234;v .v qapplication:postevent(mainwin, new qcustomevent(myevent);v 事件必须是qcustomevent类型(或子类)的。v 构造函数的参数是事件的类型,1000以下被qt保留。其他可被程序使用。为处理定制事件类型,要重新实现customevent()函数:qt的事件机制的事件机制v v

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论