Overriding QWidget Events

For the most part, Qt comes with a bunch of convenience widgets built on top of their own QWidget. They may provide very specific features and might suit your needs perfectly. But when you want to implement something that is really unique, then you’ll have to be able to engage the internal processes that make your user-friendly interactions so intuitive. One way is to override QWidget’s default events.

The most common aspects of GUI interaction you might want to take over are mouse, keyboard, or painting events. QWidget has the following protected functions keyPressEvent, keyReleaseEvent, mousePressEvent, mouseMoveEvent, mouseReleaseEvent, paintEvent. By overriding any of these protected functions, you can customize how the QWidget operates.

For example, you might want to determine what the mouse coordinates are within your QWidget. Possible usage for this is to create a point-and-click game or to determine hotspots in your own custom QWidget.

Before we get into any coding, please look at my Hello World Tutorial which shows you how to setup the minimum mainWindow widget.

Mouse Tracking

To determine the current mouse coordinates in your QWidget, you first need to override the default mouseMoveEvent. In the mainWindow header (.h), make the following changes:

private:
   int mouseX;
   int mouseY;

protected:
   void mouseMoveEvent(QMouseEvent *event);
   void paintEvent(QPaintEvent *);

overrideWid_mouseMoveHeader

overrideWid_mouseVarsHeader

Then, in the mainWindow class file (.cpp), make the following changes:

#include "QPainter"

MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
    ui(new Qt::MainWindow)
{

   ui->setupUI(this);

   this->setMouseTracking(true); //this is required to read mouseMoveEvent xy-position
   ui->centralWidget->setMouseTracking(true); //have to set both ways in order to work properly, dont know why

   //always initialize your custom variables
   mouseX = 0;
   mouseY = 0;
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
   mouseX = event.x();
   mouseY = event.y();
   this.update(); //add the instruction to repaint the widget to a list of paint instructions
}

void MainWindow::paintEvent(QPaintEvent *)
{
   QPainter painter(this);
   painter.drawText(QRect(20,20,200,200), QString::number(mouseX) + "," + QString::number(mouseY));
   painter.end();
}

overrideWid_mouseVarsInit

Now run it. If you set it correctly, you will notice the relative mouse coordinates of the QWidget mainWindow being painted to itself. Isn’t that cool?

overrideWid_finalA

Keyboard capture

Sometimes, you want to capture keyboard events, for example to implement controls for a game character. Otherwise, usually, you won’t need to capture the keyboard events without creating more conflicts than necessary. But, I’m making a game engine, so here’s how.

In the mainWindow header file, add two new private variables:

private:
   int drawX;
   int drawY;

In the mainWindow header file, add a new symbol to override the default keyPressEvent:

protected:
   void keyPressEvent(QKeyEvent *event);

overrideWid_keybdHeader

In the mainWindow class file, add a new include reference to QKeyEvent:

#include "QKeyEvent"

In the mainWindow constructor, add:

this.setFocusPolicy(Qt::StrongFocus); //required for widget to accept keyboard events

//always initialize your custom variables
drawX = 0;
drawY = 0;

overrideWid_keybdInit

And add custom event handler:

void MainWindow::keyPressEvent(QKeyEvent *event)
{
  switch (event->key())
  {
    case (Qt::Key_Left):
       drawX--;
       break;
    case (Qt::Key_Right):
       drawX++;
       break;
    case (Qt::Key_Up):
       drawY--;
       break;
    case (Qt::Key_Down):
       drawY++;
       break;
  }

  this.update();
}

overrideWid_keyPressEv

And change your paintEvent function:

void MainWindow::paintEvent(QPaintEvent *)
{
   QPainter painter(this);
   painter.drawText(QRect(drawX + 20,drawY + 20,200,200), QString::number(mouseX) + "," + QString::number(mouseY));
   painter.end();
} 

overrideWid_keyPaintA

Now run it, and when you press the arrow keys on your keyboard, you will notice that you are moving the position where the mouse coordinates are being drawn to! Neat, huh?

overrideWid_finalB

More Painting

Now that you have some basic understanding of user input/output interaction, you can start doing some really fancy stuff. Further elaborating on the draw-to-new-position example above, now I will show you how to draw an object where your mouse coordinates are.

You can simply change the drawText parameters, in the paintEvent function, from drawX to mouseX and drawY to mouseY:

painter.drawText(QRect(mouseX + 20,mouseY + 20,200,200), QString::number(mouseX) + "," + QString::number(mouseY));

But it’s more fun to draw shapes. Add this to your paintEvent:

painter.fillRect(QRect(mouseX,mouseY,80,80), QColor(Qt::red));

overrideWid_finalC

Now, you have a red box where your mouse cursor is! It’s stuck on it like glue. Pretty neat, huh?

This is the foundation of any 2D games you play. User inputs, your software outputs. You can experiment around with other gimmicks. Happy coding!