1. Qt事件系统:事件过滤器和事件的发送
Qt事件系统提供了事件过滤器功能,允许部件监控其他多个部件的事件。事件过滤器由installEventFilter()和eventFilter()函数组成,分别用于安装和处理事件。在myEventFilter项目中,Widget类构造函数中使用installEventFilter()为textEdit和spinBox部件安装过滤器,eventFilter()函数在Widget类中重新实现,用于截获并处理两个子部件事件。在处理事件时,首先判断部件类型,其次判断事件类型。对于特定事件,返回true处理该事件,否则返回false以避免重复处理。textEdit部件通过滚轮实现内容放大或缩小,spinBox部件则通过空格设置数值为0。
Qt事件系统还支持事件发送功能,由QCoreApplication类的sendEvent()和postEvent()函数实现。sendEvent()立即处理事件,postEvent()将事件放入等待调度队列,直至下一次主事件循环运行时处理。sendEvent()中的QEvent对象在事件发送后无法自动删除,必须在栈上创建。而postEvent()中的QEvent对象在堆上创建,事件队列自动删除。在widget.cpp文件构造函数中,通过sendEvent()向spinBox部件发送向上方向键被按下的事件。
运行程序时,spinBox部件初始值变为了1,证实已成功发送事件。滚动前后的效果图如下所示,显示了使用事件过滤器和发送事件功能的直观效果。
2. Qt如何捕获键盘事件
您好,Qt键盘事件属于Qt事件系统,所以事件系统中所有规则对按键事件都有效。下面关注点在按键特有的部分:
focus
一个拥有焦点(focus)的QWidget才可以接受键盘事件。有输入焦点的窗口是活动窗口或活动窗口子窗口或子子窗口等。
焦点移动的方式有以下几种:
按下Tab或Shift+Tab
注意:文本编译器(一般需要插入Tab),或者WebView(需要Tab来移动超链接焦点) 等
Qt中,需要输入Tab的地方可以用 Ctrl+Tab 或 Ctrl+Shift+Tab 替代。
点击一个QWidget
建议:只对接受文本输入的Widget启用该功能
按下键盘的快捷键
QLabel::setBuddy(), QGroupBox,以及 QTabBar 支持
使用鼠标滚轮
用户移动焦点
程序将决定被设置focus的Widget的哪一个子Widget获得焦点
注意:如果一个 Widget 已经 grabKeyboard,所有键盘事件将发送到该Widget而不是获得焦点的Widget
focusPolicy
一个QWidget获得焦点的方式受 focusPolicy 控制
Qt::TabFocus
通过Tab键获得焦点
Qt::ClickFocus
通过被单击获得焦点
Qt::StrongFocus
可通过上面两种方式获得焦点
Qt::NoFocus
不能通过上两种方式获得焦点(默认值),setFocus仍可使其获得焦点
keypress和keyrelease
首先,我们要是Widget获得焦点,一般设置focusPolicy。
然后要对按键进行响应,我们只需要直接重载:
keyPressEvent
keyReleaseEvent
注意:
对我们不处理的事件,要调用父类的相应事件处理函数。
如果widget当前没有焦点,考虑到事件转发:如果其子widget有焦点,那么该widget未处理的键盘事件将被转发过来。
有时输入焦点不在任何窗口中。这种情况发生在所有程序都是最小化的时候。这时,Windows将继续向活动窗口发送键盘消息,但是这些消息与发送给非最小化的活动窗口的键盘消息有不同的形式。
QKeyEvent
在windows下,与键盘事件有关的有8个消息:
对产生可显示字符的按键组合,Windows不仅给程序发送按键消息,而且还发送字符消息
有些键不产生字符,这些键包括shift键、功能键、光标移动键和特殊字符键如Insert和Delete。对于这些键,Windows只产生按键消息。
这些消息在Qt中只体现在QKeyEvent中。
对字符,可通过 QKeyEvent::text() 获得
其他键,QKeyEvent::key() 获得一个键值
event函数
由于 Tab 键被用来切换焦点,这使得它与众不同。
这是qwidget.cpp的event函数中的代码片段:
case QEvent::KeyPress:
{
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier)))
{ //### Add MetaModifier?
if (k->key() == Qt::Key_Backtab || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
else if (k->key() == Qt::Key_Tab)
res = focusNextPrevChild(true);
if (res)
break;
}
keyPressEvent(k);
}
如果我们需要处理Tab键,需要重载 event 函数。
3. QT原理与源码分析之对象级QT事件过滤器
本文简述了QT原理与源码分析中的对象级事件过滤器。首先介绍了如何自定义过滤函数,接着阐述了对象级事件过滤器的安装过程,最后详细分析了安装函数的源码实现。
自定义QT事件过滤器的过滤函数,需在main函数中进行安装。通过此步骤,可以实现对QT框架中特定事件的过滤与处理,增强程序的灵活性和功能性。
在安装QT事件过滤器的源代码部分,明确展示了安装函数的具体实现。这为开发者提供了实现对象级事件过滤器的步骤指南,便于开发者根据需求进行调用与定制。
进一步,分析了QT对象级别事件过滤器在框架中的调用源代码。这一部分深入探讨了过滤器在实际应用场景中的运作机制,为开发者提供了一个全面理解与实践对象级事件过滤器的路径。
总结来看,QT框架不仅支持对象级事件过滤器,还提供了应用级事件过滤器。两者在原理和源码实现上具有高度相似性,但本文重点聚焦于对象级事件过滤器。通过详细解析安装函数和调用过程,旨在为开发者提供一套实用的实践指南,助力提升程序处理特定事件的能力。
4. Qt5 事件(event)机制详解
事件机制是Qt中最复杂且精妙的部分。事件分为两种主要类型,在用户与界面交互时产生,如按下鼠标等操作。这些事件以QEvent对象的形式出现,并通过组件的event函数进行分发。事件对象包含多种属性,允许事件处理函数根据不同的情况作出响应。例如,当鼠标左键按下时,可以调用特定的事件处理函数,如mousePressEvent,根据QMouseEvent对象的属性进行相应的操作。
所有事件类都是QEvent类的子类。在处理事件时,首先需要创建自定义的类,继承自QLabel或类似的基本类,然后重写相应的事件处理函数。Qt的主程序中需要创建QApplication对象,并调用exec函数启动事件循环,持续监听应用程序的事件。当事件发生时,会生成一个QEvent对象,事件循环会将此对象传入event函数进行分发。
事件的分发通过事件处理器(event handler)完成,事件处理器函数(如mousePressEvent)在事件分发前执行。event函数是一个虚函数,接收一个QEvent类型的参数,当系统生成事件时,会调用此函数。返回值是bool类型,指示是否已处理事件。如果返回true,Qt认为事件已处理完毕,不会将其发送给其他对象,而是继续处理事件队列中的下一个事件。反之,如果返回false,事件将继续传递。
Qt中有一种机制叫做事件传播机制,允许子组件的事件在触发事件处理器后,继续传递给父组件的event函数进行处理。这种机制通过event函数的返回值来控制。
当使用自定义的事件处理器函数时,最好在事件处理完毕后调用父类的event函数,以便处理其他类型的事件。如果没有调用父类函数,将导致事件无法传播到更高层次的组件。
事件过滤器(evenFilter)机制允许拦截特定组件的事件,阻止其向其他组件传播。通过为组件或其父组件安装事件过滤器,可以实现特定功能,如在事件处理之前进行自定义操作。事件过滤器也是通过虚函数实现的,接受事件对象和组件对象作为参数。返回true表示事件被拦截,不会继续传递;返回false则表示事件将继续传递。
在实际应用中,可以将事件过滤器应用于QApplication或QCoreApplication对象,以实现全局的事件过滤。需要注意的是,事件过滤器和安装过滤器的组件必须在同一线程运行,否则过滤器可能无法正常工作。如果组件和过滤器在不同线程间移动,只有当它们回到同一线程时过滤器才会生效。
在使用Qt的事件机制时,应遵循以下步骤:识别事件类型,创建自定义事件处理函数,实现事件分发,利用事件过滤器拦截和处理特定事件。同时,应考虑事件传播机制和事件处理器的返回值,确保事件正确处理和传播。