Event Filters in Qt


Introduction

An event is an object that inherits QEvent class in Qt. Events are delivered to objects which inherits from QObject through calling QObject::event(). Event delivery means that an event has occurred, the QEvent indicates precisely what, and the QObject needs to respond. Most events are specific to QWidget and its subclasses. However, there are important events that aren't related to graphics (For example socket activation) which is the event used by QSocketNotifier for its work.

Some events come from the window system (Eg. QMouseEvent), some from other sources (Eg. QTimerEvent), and some comes from the application program. Qt is symmetric, as usual, so you can send events in exactly the same ways as Qt's own event loop does.



Installing the Event Filter

Event filter is a method used to capture the relevant or interested event using QEvent class. If it is installed on a widget and gives us a chance to manipulate events before they reach that widget. Every QObject class can be installed as an Event Filter, and all it needs to do is implement the eventFilter(QObject *obj, QEvent *evt) method. The method should return "true" if we want to block the event (so it won't reach the target widget), or false if it can pass through the filter.

Best thing about Event Filtering is that in many cases it saves us from subclassing a native widget. Here's a simple use case of counting the backspace clicks on a TextEdit.

Understand with an example

 The below example will give you a clear picture about the Event filter.

main.cpp

#include "mainwindow.h"
#include <qapplication>
#include <qtgui>
#include <qdebug>

int main(int argc, char **argv)
{

  QApplication app(argc, argv);

  MainWindow mw;
  mw.show();

  app.exec();

}

 

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <qmainwindow>
#include <qtextedit>
#include <qlabel>


namespace Ui {
class MainWindow;
}


class MainWindow : public QMainWindow
{
  public:
    MainWindow();


  protected:
    bool eventFilter(QObject *obj, QEvent *ev);


  private:
    QTextEdit *textEdit;
    QLabel    *bpCounter;
    QLabel    *bpTab;
    int        bpCnt;
    int        tabCnt;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QKeyEvent>

MainWindow::MainWindow()
{
  bpCnt = 0;
  tabCnt = 0;

  bpCounter = new QLabel(QString("Backspace Count: %1").arg(bpCnt));
  bpTab = new QLabel(QString("Tab Count: %1").arg(tabCnt));

  textEdit = new QTextEdit;
  setCentralWidget(textEdit);

  statusBar()->addWidget(bpCounter);
  statusBar()->addWidget(bpTab);
  textEdit->installEventFilter(this);
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
  if (obj == textEdit) {
    if (event->type() == QEvent::KeyPress) {
      QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
      if ( keyEvent->key() == Qt::Key_Backspace ) {
        bpCounter->setText(QString("Backspace Count: %1").arg(bpCnt++));
      }
      else if ( keyEvent->key() == Qt::Key_Tab )
      {
        // 4 spaces
        textEdit->insertPlainText(QString().fill(' ', 4));
        bpTab->setText(QString("Tab Count: %1").arg(tabCnt++));
        return true;
      }
    }

    // pass the event to the widget
    return false;
  }
  else {
    // pass the event on to the parent class
    return QMainWindow::eventFilter(obj, event);
  }
};