一、事件
1.事件与信号的区别
事件来自外部,是随机 发生的。信号来自内部,是主动 发生的。有点像外中断和内中断的区别。 事件:适用于处理系统级别的输入和状态变化,种类繁多,能够应对复杂的交互 需求。 信号/槽:适用于对象间通信和状态变化响应,灵活性高,支持异步通信和多线程编程。 信号是单调的,而事件是丰富的。
2.事件系统QEvent
GUI(Graphical User Interface) 应用程序是由事件(event)驱动的,点击鼠标、按下某个按键、改变窗口大小、最小化窗口等都会产生相应的事件,应用程序对这些事件进行相应的处理以实现程序的功能。 在大多数情况下,GUI进程和UI进程这两个术语是可以互换使用的,它们通常指的是同一个概念,即处理和管理图形用户界面(Graphical User Interface, GUI)以及用户与应用程序交互的进程。 代码详解
#include "widget.h"#include < QApplication> int main(int argc, char *argv[])
{QApplication a(argc, argv);
//QApplication类是Qt应用程序的核心,负责管理应用程序的控制流和主要设置。
通过构造函数QApplication::QApplication(int &argc, char **argv)创建
一个QApplication对象。这个对象初始化应用程序的环境,并且启动事件循环。Widget w;w.show();
//Widget w;创建一个名为w的Widget对象(假设Widget是自定义的窗口类,继承自QWidget或其子类)。
w.show();调用QWidget的show()方法,使窗口显示在屏幕上。显示窗口后,QWidget开始接收和处理事件。return a.exec();//a.exec()启动Qt的主事件循环。这是一个阻塞调用,直到应用程序退出(通常是通过调用QApplication::quit()或窗口关闭事件)。
在事件循环中,QApplication会持续监控事件队列,等待并处理各种事件,如鼠标点击、键盘输入、窗口重绘请求等。
}
3. 事件过滤器
事件过滤器。它可以将一个对象的事件委托给另一个对象来监视并处理。例如,一个窗口可以作为其界面上的QLabel组件的事件过滤器,派发给QLabel 组件的事件由窗口去处理,这样,就不需要为了处理某种事件而新定义一个标签类。 要实现事件过滤器功能,需要完成两项操作。 - 被监视对象使用函数installEventFilter()将自己注册给监视对象,监视对象就是事件过滤器。 - 监视对象重新实现函数eventFilter(),对监视到的事件进行处理。作为事件过滤器的监视对象需要重新实现函数eventFilter() 事件过滤器可以在事件到达目标对象之前进行预处理,从而提供了更多的控制和灵活性。 主要作用和使用场景 1. 事件拦截和预处理 - 检查 和修改 事件:在事件到达目标对象之前检查和修改事件。例如,可以在事件到达目标对象之前记录事件信息、修改事件数据或阻止事件的进一步传播。 - 实现自定义逻辑 :在事件到达目标对象之前实现自定义逻辑。例如,可以在鼠标点击之前判断是否允许特定操作,或者在键盘输入之前进行输入验证。 2. 统一处理 多个对象的事件 - 事件过滤器允许你统一处理多个对象的事件,而不需要在每个对象上实现事件处理函数。这对于管理复杂界面中的多个控件特别有用。 - 集中 处理事件:将事件处理逻辑集中到一个地方(即事件过滤器),而不是在每个控件的事件处理函数中实现。 - 简化代码:减少代码重复,使代码更清晰、易于维护。 3. 实现复杂的事件处理逻辑 - 拦截 和阻止 事件:根据需要阻止事件的进一步传播。例如,可以阻止鼠标事件在控件之间传播,或者阻止特定的键盘输入。 - 实现全局事件处理 :在整个应用程序中实现全局事件处理逻辑,例如处理所有控件的鼠标点击事件。 4. 使用场景 - 自定义控件行为 :修改控件的默认行为,例如在按钮上添加额外的点击处理逻辑。 - 事件监控 :记录或调试事件,例如记录所有鼠标点击事件的位置和类型。 - 跨控件事件处理 :在一个地方集中处理多个控件的事件,例如处理所有按钮的点击事件。
4. 代码举例
# ifndef WIDGET_H
# define WIDGET_H # include <QWidget> QT_BEGIN_NAMESPACE
namespace Ui { class Widget ; }
QT_END_NAMESPACE
class Widget : public QWidget
{ Q_OBJECT public : Widget ( QWidget * parent = nullptr ) ; ~ Widget ( ) ; bool eventFilter ( QObject * watched, QEvent * event) override ; public slots:
void btnClickedSlotFun ( ) ; private : Ui:: Widget * ui;
} ; # endif
# include "widget.h"
# include "ui_widget.h"
# include <QDebug>
# include <QMouseEvent> Widget :: Widget ( QWidget * parent) : QWidget ( parent) , ui ( new Ui:: Widget)
{ ui-> setupUi ( this ) ; ui-> label-> installEventFilter ( this ) ; ui-> btn-> installEventFilter ( this ) ; ui-> labHover-> installEventFilter ( this ) ; ui-> labDBClick-> installEventFilter ( this ) ; connect ( ui-> btn, SIGNAL ( clicked ( ) ) , this , SLOT ( btnClickedSlotFun ( ) ) ) ;
} Widget :: ~ Widget ( )
{ delete ui;
} bool Widget :: eventFilter ( QObject * watched, QEvent * event)
{ if ( watched == ui-> label) { if ( event-> type ( ) == QEvent:: MouseButtonPress) { QMouseEvent * ev = static_cast < QMouseEvent * > ( event) ; qDebug ( ) << "label press" << ev-> button ( ) << "x=" << ev-> x ( ) << "y=" << ev-> y ( ) ; } else if ( event-> type ( ) == QEvent:: Enter) { qDebug ( ) << "label enter" ; } else if ( event-> type ( ) == QEvent:: Leave) { qDebug ( ) << "label leave" ; } } else if ( watched == ui-> btn) { if ( event-> type ( ) == QEvent:: Enter) { static int a = 1 ; ui-> lineEdit-> setText ( QString ( "zhangsan = %1" ) . arg ( a++ ) ) ; qDebug ( ) << "btn enter" ; } else if ( event-> type ( ) == QEvent:: Leave) { qDebug ( ) << "btn leave" ; } } else if ( watched == ui-> labHover) { if ( event-> type ( ) == QEvent:: Enter) { ui-> labHover-> setStyleSheet ( "background-color: rgb(170, 255, 255);" ) ; } else if ( event-> type ( ) == QEvent:: Leave) { ui-> labHover-> setStyleSheet ( "" ) ; ui-> labHover-> setText ( "靠近我,点击我" ) ; } else if ( event-> type ( ) == QEvent:: MouseButtonPress) { ui-> labHover-> setText ( "button pressed" ) ; } else if ( event-> type ( ) == QEvent:: MouseButtonRelease) { ui-> labHover-> setText ( "button released" ) ; } } else if ( watched == ui-> labDBClick) { if ( event-> type ( ) == QEvent:: Enter) { ui-> labDBClick-> setStyleSheet ( "background-color: rgb(85, 255, 127);" ) ; } else if ( event-> type ( ) == QEvent:: Leave) { ui-> labDBClick-> setStyleSheet ( "" ) ; ui-> labDBClick-> setText ( "可双击的标签" ) ; } else if ( event-> type ( ) == QEvent:: MouseButtonDblClick) { ui-> labDBClick-> setText ( "double clicked" ) ; } } return QWidget :: eventFilter ( watched, event) ;
} void Widget :: btnClickedSlotFun ( )
{ static int c = 1 ; qDebug ( ) << "c = " << c;
}
5. QT事件类型
Qt事件类型
事件类 事件类型 事件描述 QMouseEvent
QEvent::MouseButtonDblClick
鼠标双击 QEvent::MouseButtonPress
鼠标按键按下,可以是左键或右键 QEvent::MouseButtonRelease
鼠标按键释放,可以是左键或右键 QEvent::MouseMove
鼠标移动 QWheelEvent
QEvent::Wheel
鼠标滚轮滚动 QHoverEvent
QEvent::HoverEnter
鼠标光标移动到组件上方并悬停(hover) QEvent::HoverLeave
鼠标光标离开某个组件上方 QEvent::HoverMove
鼠标光标在组件上方移动 QEnterEvent
QEvent::Enter
鼠标光标进入组件或窗口边界范围内 QEvent
QEvent::Leave
鼠标光标离开组件或窗口边界范围 QKeyEvent
QEvent::KeyPress
键盘按键按下 QEvent::KeyRelease
键盘按键释放 QFocusEvent
QEvent::FocusIn
组件或窗口获得键盘的输入焦点 QEvent::FocusOut
组件或窗口失去键盘的输入焦点 QEvent::FocusAboutToChange
组件或窗口的键盘输入焦点即将变化 QShowEvent
QEvent::Show
窗口在屏幕上显示出来,或组件变得可见 QHideEvent
QEvent::Hide
窗口在屏幕上隐藏(例如窗口最小化),或组件变得不可见 QMoveEvent
QEvent::Move
组件或窗口的位置移动 QCloseEvent
QEvent::Close
窗口被关闭,或组件被关闭,例如QTabWidget的一个页面被关闭 QPaintEvent
QEvent::Paint
界面组件需要更新重绘 QResizeEvent
QEvent::Resize
窗口或组件改变大小 QStatusTipEvent
QEvent::StatusTip
请求显示组件的statusTip信息 QHelpEvent
QEvent::ToolTip
请求显示组件的toolTip信息 QEvent::WhatsThis
请求显示组件的whatsThis信息 QDragEnterEvent
QEvent::DragEnter
在拖放操作中,鼠标光标移动到组件上方 QDragLeaveEvent
QEvent::DragLeave
在拖放操作中,鼠标光标离开了组件 QDragMoveEvent
QEvent::DragMove
拖放操作正在移动过程中 QDropEvent
QEvent::Drop
拖放操作完成,即放下拖动的对象 QTouchEvent
QEvent::TouchBegin
开始一个触屏事件序列(sequence) QEvent::TouchCancel
取消一个触屏事件序列 QEvent::TouchEnd
结束一个触屏事件序列 QEvent::TouchUpdate
触屏事件 QGestureEvent
QEvent::Gesture
手势事件,能识别的手势有轻触、放大、扫屏等 QNativeGestureEvent
QEvent::NativeGesture
操作系统检测到手势而产生的事件 QActionEvent
QEvent::ActionAdded
运行QWidget::addAction()函数时会产生这种事件 QEvent::ActionChanged
Action改变时触发的事件 QEvent::ActionRemoved
移除Action时触发的事件