`
soboer
  • 浏览: 1369931 次
文章分类
社区版块
存档分类
最新评论

QT编程----事件(二)

 
阅读更多

eventFilter事件过滤器

Qt事件模型一个真正强大的特色是一个QObject的实例能够管理另一个QObject实例的事件。

一个CustomerDialog的小部件。CustomerDialog包含一系列QLineEdit.现在,我们想用空格键来代替Tab,使焦点在这些QLineEdit间切换。

一个解决的方法是子类化QLineEdit,重新实现keyPressEvent(),并在keyPressEvent()里调用focusNextChild()。像下面这样:

voidMyLineEdit::keyPressEvent(QKeyEvent*event)

{

if(event->key()==Qt::Key_Space){

focusNextChild();

}else{

QLineEdit::keyPressEvent(event);

}

}

上述做法有一个缺点。如果CustomerDialog里有很多不同的控件(比如QComboBox,QEdit,QSpinBox),我们就必须子类化这么多控件。这是一个烦琐的任务。

一个更好的解决办法是:让CustomerDialog去管理他的子部件的按键事件,实现要求的行为。我们可以使用事件过滤器。

一个事件过滤器的安装需要下面2个步骤:

1,调用installEventFilter()注册需要管理的对象。

2,在eventFilter()里处理需要管理的对象的事件。

一般,推荐在CustomerDialog的构造函数中注册被管理的对象。像下面这样:

CustomerInfoDialog::CustomerInfoDialog(QWidget*parent):QDialog(parent)

{...

firstNameEdit->installEventFilter(this);

lastNameEdit->installEventFilter(this);

cityEdit->installEventFilter(this);

phoneNumberEdit->installEventFilter(this);

}

一旦,事件管理器被注册,发送到firstNameEditlastNameEditcityEditphoneNumberEdit的事件将首先发送到eventFilter()

下面是一个eventFilter()函数的实现:

boolCustomerInfoDialog::eventFilter(QObject*target,QEvent*event)

{

if(target==firstNameEdit||target==lastNameEdit

||target==cityEdit||target==phoneNumberEdit){

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

QKeyEvent*keyEvent=static_cast<QKeyEvent*>(event);

if(keyEvent->key()==Qt::Key_Space){

focusNextChild();

returntrue;

}

}

}

returnQDialog::eventFilter(target,event);

}

在上面的函数中,我们首先检查目标部件是否是firstNameEditlastNameEditcityEditphoneNumberEdit。接着,我们判断事件是否是按键事件。如果事件是按键事件,我们把事件转换为QKeyEvent。接着,我们判断是否按下了空格键,如果是,我们调用focusNextChild(),把焦点传递给下一个控件。然后,返回,true通知Qt,我们已经处理了该事件。

如果返回false的话,Qt继续将该事件发送给目标控件,结果是一个空格被插入到QLineEdit中。

如果目标控件不是QLineEdit,或者按键不是空格键,我们将把事件传递给基类的eventFilter()函数。

Qt提供5个级别的事件处理和过滤:

1,重新实现事件函数。比如:mousePressEvent(),keyPress-Event(),paintEvent()。这是最常规的事件处理方法。

2,重新实现QObject::event().

这一般用在Qt没有提供该事件的处理函数时。也就是,我们增加新的事件时。

3,安装事件过滤器

4,在QApplication上安装事件过滤器。

QApplication上的事件过滤器将捕获应用程序的所有事件,而且第一个获得该事件。也就是说事件在发送给其它任何一个eventfilter之前发送给QApplicationeventfilter

5,重新实现QApplicationnotify()方法.

Qt使用notify()来分发事件。要想在任何事件处理器捕获事件之前捕获事件,唯一的方法就是重新实现QApplicationnotify()方法。

在创建了过滤器之后,下面要做的是安装这个过滤器。安装过滤器需要调用installEventFilter()函数。这个函数的签名如下:

 voidQObject::installEventFilter(QObject*filterObj)

这个函数是QObject的一个函数,因此可以安装到任何QObject的子类,并不仅仅是UI组件。这个函数接收一个QObject对象,调用了这个函数安装事件过滤器的组件会调用filterObj定义的eventFilter()函数。

例如,textField->installEventFilter(obj),则如果有事件发送到textField组件是,会先调用obj->eventFilter()函数,然后才会调用textField->event()

也可以把事件过滤器安装到QApplication上面,这样就可以过滤所有的事件,已获得更大的控制权。不过,这样做的后果就是会降低事件分发的效率。

如果一个组件安装了多个过滤器,则最后一个安装的会最先调用,类似于堆栈的行为。

pushButton2=newQPushButton(this,"pushButton2");

pushButton2->setGeometry(QRect(200,160,111,31));

pushButton2->installEventFilter(this);

boolForm1::eventFilter(QObject*o,QEvent*e)

{

if(pushButton2==o)

{

if(e->type()==QEvent::KeyPress)

{

QKeyEvent*k=(QKeyEvent*)e;

qDebug("eatkeypress%d",k->key());

returnTRUE;

}

if(e->type()==QEvent::MouseButtonPress)

{

QMouseEvent*k=(QMouseEvent*)e;

qDebug("eatMousepress");

returnTRUE;

}

else{

returnFALSE;

}

}

else

returnQWidget::eventFilter(o,e);

}

boolForm1::event(QEvent*event)

{

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

{

QKeyEvent*keyEvent=(QKeyEvent*)event;

if(keyEvent->key()==Key_A)

{

qDebug("--cuttheKey_A--\n");

returntrue;

}

}

returnQWidget::event(event);

}

事件的产生

QT应用程序可以产生自定义的事件,或是预定义类型,或是自定义类型。这可以通过创建QEvent类或它的子类的实例,并且调用QApplication:postEvent()QApplication::sendEvent()来实现。

这两个函数需要一个QObject*与一个QEvent*作为参数,假如你调用postEvent(),你必须用new操作符来创建事件对象,Qt会它被处理后帮你删除它。

假如你用sendEvent(),你应该在栈上来创建事件。

下面举两个例子:

一是posting事件:

QApplication::postEvent(mainWin,new

QKeyEvent(QEvent::KeyPress,Key_X,'X',0,"X"));

二是sending事件:

QKeyEventevent(QEvent::KeyPress,Key_X,'X',0,"X");

QApplication::sendEvent(mainWin,&event);

Qt应用程序很少直接调用postEvent()或是sendEvnet(),因为大多数事件会在必要时被Qt或是窗口系统自动产生。在大多数的情况下,当你想发送一个事件时,Qt已经为你准备好了一个更高级的函数来为你服务。(例如update()repaint())

为了提高qt程序的自定义特性,可以显式得采用程序实现事件的发送。

重绘事件paintEvent()

当窗口被其他窗口覆盖后,再次重新显示时,系统将产生spontaneous事件来请求重绘,事件循环最终从事件队列中捡选这个事件并把它分发到那个需要重画的widget

当我们调用QWidget::update()时,产生的是Posted重绘事件

当我们调用QWidget::repaint()时,产生的是Sent重绘事件

posting相对于sending的一个优势是,它给了Qt一个压缩(compress)事件的机会。假如你在一个widget上连续地调用update()十次,因update()而产生的这十个事件,将会自动地被合并为一个单独的事件,但是QPaintEvents事件附带的区域信息也合并了。

可压缩的事件类型包括:paint,move,resize,layouthint,languagechange

最后要注意,可以在任何时候调用QApplication::sendPostedEvent(),强制Qt产生一个对象的posted事件。

Qt系统还提供了一个QCustomEvent类,用于用户自定义事件,这些自定义事件可以利用QThread::postEvent()或者QApplication::postEvent()被发给各种控件或其他QObject实例。

QWidget类的子类可以通过QWidget::customEvent()事件处理函数方便地接收到这些自定义的事件。

需要注意的是:QCustomEvent对象在创建时都带有一个类型标识id以定义事件类型,为了避免与Qt系统定义的事件类型冲突,该id值应该大于枚举类型QEvent::Type中给出的"User"值。

演示如何post一个定制事件的代码片段:

constQEvent::TypeMyEvent=(QEvent::Type)1234;

...

QApplication::postEvent(mainwin,newQCustomEvent(MyEvent));

事件必须是QCustomEvent类型(或子类)的。

构造函数的参数是事件的类型,1000以下被Qt保留。其他可被程序使用。为处理定制事件类型,要重新实现customEvent()函数:

voidMyWin::customEvent(QCustomEvent*event)

{

if(event->type()==MyEvent){

myEvent();

}else{

Qwidget::customEvent(event);

}

}

QcustomEvent类有一个void*的成员,可用于特定的目的。你也可以子类化QCustomEvent,加上别的成员。

一些事件类型可以被传递。这意味着假如目标对象不处理一个事件,Qt会试着寻找另外的事件接收者。用新的目标来调用QApplication::notify()

举例来讲,key事件是传递的,假如拥有焦点的Widget不处理特定键,Qt会分发相同的事件给父widget,然后是父亲的父亲,直到最顶层widget

可被传递的事件可以接收或是忽略这个事件。假如事件被处理,这个事件将不会再被传递。否则Qt会试着查找另外的事件接收者。

大部分qt对象对事件的处理缺省情况下是接收,在QWidget中的缺省实现是调用忽略”,假如你希望接收事件,你需要做的是重新实现事件handler,避免调用QWidget的实现。假如你想忽略事件,只需简单地传递它到QWidget的实现。

下面的代码演示了这一点:

voidMyWidget::keyPressEvent(QKeyEvent*event)

{

if(event->key()==Key_Escape){

doEscape();

}else{

QWidget::keyPressEvent(event);

}

}

在上面的例子里,假如用户按了"ESC"键,我们会调用doEscape()并且事件被接收了(这是缺省的情况),事件不会被传递到父widget,假如用户按了别的键,则调用QWidget的缺省实现。

voidQWidget::keyPressEvent(QKeyEvent*event)

{

event->ignore();

}

此处调用ignore(),事件会被传递到父widget中去。

以上假设基类都是QWidget,然而,同样的规则也可以应用到别的层次中,只要用其他基类代替QWidget即可。

举例来说:

voidMyLineEdit::keyPressEvent(QKeyEvent*event)

{

if(event->key()==Key_SysReq){

doSystemRequest();

}else{

QLineEdit::keyPressEvent(event);

}

}

分享到:
评论

相关推荐

    QT编程----事件

    在 QT 编程中,事件处理机制是非常重要的一部分。事件是指用户与应用程序之间的交互操作,例如点击按钮、移动鼠标、键盘输入等。QT 事件处理机制可以分为三类:Spontaneous 事件、Posted 事件和 Sent 事件。 ...

    QT编程手册----QT编程手册---学习QT的C++编程

    QT编程是C++开发者在构建图形用户界面(GUI)应用时的一个强大工具。QT库提供了丰富的功能,使得开发者能够创建跨平台的应用程序,运行在Windows、Linux、macOS、Android和iOS等操作系统上。QT的核心理念是“编写一...

    qt-vs-addin-1.2.5+qt-creator-5.0.3

    QT是一个开源的跨平台应用程序开发框架,主要用于C++编程,由Qt Company维护并提供支持。在给定的压缩包文件中,我们有两个关键组件:qt-vs-addin-1.2.5和qt-creator-5.0.3。 首先,qt-vs-addin-1.2.5是Visual ...

    qttools-everywhere-src-5.15.0.zip

    学习和研究“qttools-everywhere-src-5.15.0”中的源代码,不仅可以加深对Qt框架的理解,还能提升我们的C++编程技巧,同时对于想要进行Qt工具定制的开发者来说,这是一个宝贵的资源。通过阅读源码,我们可以学习到...

    qt5.12.1-qt-opensource-linux-x64-5.12.1.run

    Qt Core:提供核心功能,如事件处理、定时器、文件处理等。 Qt GUI:提供用于创建和管理图形用户界面的工具和控件。 Qt Widgets:提供一套丰富的预制控件,如按钮、文本框、列表框等。 Qt Network:提供网络编程的...

    qtserialport-everywhere-src-6.8.0.zip

    QtSerialPort是Qt官方提供的用于串行端口通信的模块,它简化了串行通信编程,使得开发者能够以面向对象的方式来处理串行端口的通信任务。SerialPort模块为处理串行通信提供了丰富的API,包括但不限于串口配置、读写...

    qt-vsaddin-msvc2013 & qt-vsaddin-msvc2015.zip

    Qt是一个跨平台的应用程序开发框架,由Qt Company维护,主要用C++编写,但同时也支持其他编程语言,如Python(通过PyQt)。Qt广泛应用于桌面、移动和嵌入式设备上的图形用户界面和应用程序开发。它提供了一整套API,...

    QT程序调试器——qtcreator-gdb-7.4-MINGW32_NT-6.1-i686

    GDB是GNU项目的一部分,它支持多种编程语言,包括C、C++、Fortran等。在QT Creator中,GDB被用来设置断点、单步执行代码、查看变量值、跟踪调用堆栈以及控制程序执行流程。对于QT开发者来说,这意味着可以在源代码...

    qt-everywhere-opensource-src-4.8.7.7z

    在QT 4.8.7中,一些重要的模块包括QWidgets(用于桌面应用的UI)、QNetwork(处理网络通信)、QSql(数据库操作)和QThread(多线程编程)。同时,它还支持XML解析、OpenGL图形渲染以及多种文件格式的读写。由于这是...

    qt3d-everywhere-src-6.0.0.zip

    QT 3D是Qt的一个组件,专注于3D图形编程,它允许开发者构建高度定制的3D场景,同时与Qt的其他模块无缝集成。 QT 3D 6.0.0版本引入了许多改进和新特性,包括性能优化、更好的API设计以及对现代图形硬件的支持。在这...

    QT在线安装器qt-unified-windows-x64-4.6.0-online.exe

    Qt框架的核心特点包括其C++编程接口,它提供了丰富的类库,使得开发者能够构建功能强大的图形用户界面(GUI)应用。此外,Qt还支持QML(Qt Meta Language),这是一种声明性的语言,用于创建现代、动态的用户界面,...

    eclipse 集成 qtjambi插件(qtjambi-eclipse-integration-4.5.2_01)

    Eclipse是一款广泛使用的Java集成开发环境(IDE),它支持多种编程语言和开发工具。而QtJambi是Qt库的一个Java绑定,允许Java开发者利用Qt框架创建图形用户界面(GUI)。"eclipse集成qtjambi插件(qtjambi-eclipse-...

    qt-vsaddin-msvc2017

    2. **Visual Studio 2017**:微软的旗舰级开发工具,支持多种编程语言,包括C++,并提供了丰富的调试、版本控制和团队协作功能。与Qt结合,开发者可以在一个统一的环境中进行跨平台开发。 3. **Qt 5.14.2**:这是Qt...

    qtcharts-opensource-src-5.7.0.zip

    这种事件驱动的编程模式使得QtCharts在交互式应用中表现得非常灵活。 总之,“qtcharts-opensource-src-5.7.0.zip”是一个包含QtCharts模块源代码的重要资源,它为开发者提供了深入学习和定制图表功能的机会。通过...

    qt-opensource-windows-x86-msvc2012-5.6.3.exe

    qt-opensource-windows-x86-msvc2012-5.6.3 这个是在vs2012中的使用的qt 编绎时使用的命令: configure -prefix d:\win32-msvc2012 -platform win32-msvc2012 -opensource -confirm-license -nomake tests -nomake ...

    PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32

    5. `QSignal` 和 `QSlot`:实现对象间的通信机制,是Qt的信号和槽机制,是事件驱动编程的核心。 除了这些基本组件,PyQt4还提供了一整套高级组件和服务,如`QTableWidget`(表格)、`QGraphicsView`(图形视图)、`...

    qt-opensource-windows-x86-mingw482-4.8.7 Qt4.8.7是Qt4的终结版本,是Qt4系

    Qt4.8.7是Qt4的终结版本,是Qt4系列版本中最稳定最经典的(很多嵌入式板子还是用Qt4.8),其实该版本是和Qt5.5差不多时间发布的。参考链接 https://www.qt.io/blog/2015/05/26/qt-4-8-7-released ...

    qttools-everywhere-src-6.8.0.1.zip

    对于不熟悉构建过程的开发者,Qt提供了预编译的二进制安装包,以便更容易地开始使用Qt。 由于Qt支持多平台,因此Qt6.8.0源代码包具有极大的适用性。无论是Windows、Linux还是macOS等操作系统,只要遵循相应的编译...

    PyQt5-5.4.1-gpl-Py3.4-Qt5.4.1-x64

    此外,PyQt5还支持信号和槽机制,这是一种事件驱动编程模型,使得组件间的通信更加便捷。 安装PyQt5时,通常通过pip命令或下载像"PyQt5-5.4.1-gpl-Py3.4-Qt5.4.1-x64 (1).exe"这样的安装程序。在64位Windows系统上...

    PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32

    PyQt5是一个强大的工具,它将Qt库与Python编程语言结合在一起,允许开发者创建功能丰富的图形用户界面(GUI)应用程序。这个"PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32"是针对Python 3.4版本的,基于GPL许可的PyQt5版本,...

Global site tag (gtag.js) - Google Analytics