Qt所有的事件类都继承于QEvent。主要实现方式是通过通过事件对象传递给QObjectevent()函数,event()函数再按照事件对象类型来分给特定事件处理函数来处理。

常用的事件处理回调函数有

  1. [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
  2. [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event)
  3. [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
  4. [virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
  5. [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
  6. [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
  7. [virtual protected] void QWidget::enterEvent(QEnterEvent *event)
  8. [virtual protected] void QWidget::leaveEvent(QEvent *event)
  9. [virtual protected] void QWidget::dragEnterEvent(QDragEnterEvent *event)
  10. [virtual protected] void QWidget::dragLeaveEvent(QDragLeaveEvent *event)
  11. [virtual protected] void QWidget::wheelEvent(QWheelEvent *event)

这些函数均为virtual protected,且都定义于QWidget类中,因此,可以在QWidget的子类中重新实现,不过要注意定义方式。

  1. protected:
  2. void mouseMoveEvent(QMouseEvent *event);
  3. void mousePressEvent(QMouseEvent *event);
  4. void mouseReleaseEvent(QMouseEvent *event);

然后根据不同的事件类QMouseEvent去进行不同的操作。详情根据帮助文档查找有哪些操作。
如果event不使用,则在函数中添加Q_UNUSED(event); 来规避编译警告。

  1. void widget::mousePressEvent(QMouseEvent *event)
  2. {
  3. Q_UNUSED(event); //规避编译警告
  4. }

定时器事件

  1. [virtual protected] void QObject::timerEvent(QTimerEvent *event)

很明显继承于QObject类,因此可以在相应的子类中重写。
主要的函数有

  1. int QObject::startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer)
  2. void QObject::killTimer(int id)
  3. int QTimerEvent::timerId() const

其中,

startTimer()为启动定时器,参数int interval单位为毫秒 killTimer()停止定时器,参数int id则为startTimer()的返回id,通过timerId()得到

例子:

  1. class MyObject : public QObject
  2. {
  3. Q_OBJECT
  4. public:
  5. MyObject(QObject *parent = nullptr);
  6. protected:
  7. void timerEvent(QTimerEvent *event) override;
  8. private:
  9. int timer1;
  10. int timer2;
  11. int timer3
  12. };
  13. MyObject::MyObject(QObject *parent)
  14. : QObject(parent)
  15. {
  16. timer1=startTimer(50); // 50ms定时器
  17. timer2=startTimer(1000); // 1s定时器
  18. timer3=startTimer(60000); // 1minute定时器
  19. // using namespace std::chrono;
  20. // startTimer(milliseconds(50));
  21. // startTimer(seconds(1));
  22. // startTimer(minutes(1));
  23. // since C++14 we can use std::chrono::duration literals, e.g.:
  24. // startTimer(100ms);
  25. // startTimer(5s);
  26. // startTimer(2min);
  27. // startTimer(1h);
  28. }
  29. void MyObject::timerEvent(QTimerEvent *event)
  30. {
  31. if(event->timerId() == this->timer1)
  32. {
  33. static int sec = 0;
  34. sec++;
  35. if(5 == sec) //定时5*50ms时间
  36. {
  37. this->killTimer(this->timer1); //停止50ms定时器
  38. }
  39. }
  40. qDebug() << "Timer ID:" << event->timerId();
  41. }

事件的接收和忽略

在一个子类中重写事件时,要注意不会影响到父类原先信号的使用。
即事件接收后,要确保事件可以传递给父类。
例子

  1. class MyButton : public QPushButton
  2. {
  3. Q_OBJECT
  4. public:
  5. MyButton(QWidget *parent = nullptr);
  6. protected:
  7. void mousePressEvent(QMouseEvent *event);
  8. };
  9. MyButton::MyButton(QWidget *parent)
  10. : QPushButton(parent)
  11. {
  12. }
  13. void MyButton::mousePressEvent(QMouseEvent *event)
  14. {
  15. if(event->button() == Qt::LeftButton)
  16. {
  17. qDebug() << "左键按下";
  18. //事件接收后,不往下传递
  19. //标记3
  20. // event->ignore(); //事件忽略,事件继续往下传递
  21. //传递给了父组件Widget,非父类(基类)QPushButton
  22. }
  23. else
  24. {
  25. //标记1
  26. QPushButton::mousePressEvent(event);
  27. //事件忽略,事件继续往下传递
  28. }
  29. //标记2
  30. // QPushButton::mousePressEvent(event); //不影响父类的接收
  31. }
  32. class widget : public QWidget
  33. {
  34. Q_OBJECT
  35. private:
  36. MyButton *button;
  37. protected:
  38. void mousePressEvent(QMouseEvent *event);
  39. };
  40. Widget::widget(QWidget *parent)
  41. {
  42. button = new MyButton(this);
  43. connect(button,&MyButton::clicked,this[=]()
  44. {
  45. qDebug() << "按键按下";
  46. });
  47. }
  48. void Widget::mousePressEvent(QMouseEvent *event)
  49. {
  50. qDebug() << "+++++";
  51. }

在例子中,重写一个MyButton类继承于QPushButton

如果在标记1中,则只打印输出 左键按下 ,说明事件传递到此就不继续传递 如果在标记2中,则打印输出 左键按下 按键按下,通过调用父类事件函数继续传递消除影响 如果在标记3中,则打印输出 左键按下 +++++,说明事件传递给父组件,非父类

即,重写事件类时要注意不会影响基类的事件传递。

accept() 和 ignore() 函数

主要使用在closeEvent()中。

  1. void Widget::closeEvent(QCloseEvent *event)
  2. {
  3. int ret = QMessageBox::question(this,"question","是否需要关闭窗口");
  4. if(ret == QMessageBox::Yes)
  5. {
  6. //关闭窗口
  7. //处理关闭窗口事件,接收事件,事件就不会再往下传递
  8. event->accept();
  9. }
  10. else
  11. {
  12. //不关闭窗口
  13. //忽略事件,事件继续传递给父组件
  14. event->ignore();
  15. }
  16. }

事件分发函数 event()

  1. [override virtual protected] bool QWidget::event(QEvent *event)

可以看到事件是bool类型,如果传入的事件已被识别并且处理,则返回true,否则返回false。
如果返回值是true,则Qt认为该次事件已经处理完毕,不会再将该次事件发送给其他对象,而是会继续处理事件队列的下一个事件。
可以通过重写 event(),来重新进行事件分发,标记点1。
也可以通过event(),来中止某个事件,标记点2。

  1. class MyWidget : public QWidget
  2. {
  3. Q_OBJECT
  4. public:
  5. MyWidget(QWidget *parent = nullptr);
  6. protected:
  7. void event(QEvent *event) override;
  8. };
  9. MyWidget::MyWidget(QWidget *parent)
  10. : QWidget(parent)
  11. {
  12. }
  13. bool MyWidget::event(QEvent *event)
  14. {
  15. //标记点1 事件分发
  16. switch(event->type())
  17. {
  18. case QEvent::Close :
  19. {
  20. QCloseEvent *e = static_cast<QCloseEvent *>(event);
  21. closeEvent(event);
  22. return true
  23. }
  24. break;
  25. case QEvent::MouseButtonPress :
  26. {
  27. QMouseEvent *e = static_cast<QMouseEvent *>(event);
  28. mousePressEvent(e);
  29. return true;
  30. }
  31. break;
  32. /*
  33. ...
  34. */
  35. }
  36. //标记点2
  37. // if(event->type() == QEvent::Timer)
  38. // {
  39. // //干掉定时器
  40. // //如果返回true,事件停止传播
  41. // //QTimerEvent *event //需要进行event类型的强制转化
  42. // //QTimerEvent *e = static_cast<QTimerEvent *>(event);
  43. // //timerEvent(e);
  44. // return true;
  45. // }
  46. // else if()
  47. // {
  48. // //类型转换
  49. // QKeyEvent *e = static_cast<QKeyEvent *>(event);
  50. // if(e->key() == Qt::Key_B)
  51. // {
  52. // return QWidget::event(event);
  53. // }
  54. // return true;
  55. // }
  56. // else
  57. // { //
  58. // return QWidget::event(event);
  59. // }
  60. }

事件过滤器:eventFilter()

事件过滤器会检查接收到的事件,如果这个事件是我们要的,就自己处理,否则就继续转发。
这个函数返回一个bool类型,如果你想将event过滤出来,比如,不想让它继续转发,就返回true,否则返回false。

  1. [virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)

首先重写eventFilter(),然后安装事件过滤器,之后过滤事件。
例子

  1. class MainWindow : public QMainWindow
  2. {
  3. public:
  4. MainWindow();
  5. protected:
  6. bool eventFilter(QObject *obj, QEvent *ev) override;
  7. private:
  8. QTextEdit *textEdit;
  9. };
  10. MainWindow::MainWindow()
  11. {
  12. textEdit = new QTextEdit;
  13. setCentralWidget(textEdit);
  14. textEdit->installEventFilter(this); //安装事件过滤器
  15. }
  16. bool MainWindow::eventFilter(QObject *obj, QEvent *event)
  17. {
  18. if (obj == textEdit) {
  19. if (event->type() == QEvent::KeyPress) { //判断事件按键按下
  20. QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
  21. qDebug() << "Ate key press" << keyEvent->key();
  22. return true; //不让事件继续传播
  23. } else {
  24. // 按照原来的方式传播事件
  25. return QMainWindow::eventFilter(obj, event);
  26. }
  27. } else {
  28. // 按照原来的方式传播事件
  29. return QMainWindow::eventFilter(obj, event);
  30. }
  31. }

注意:事件过滤器在多线程中无效,即安装事件过滤器和过滤器要在同一个线程。