4.4. Handling User Input

Applications receive user input most commonly via mouse and keyboard. You saw earlier that mouse and keyboard information is passed to a KDE/Qt application from the window system via events. The events that are important here are

  • mousePressEvent()

  • mouseMoveEvent()

  • mouseReleaseEvent()

  • mouseDoubleClickEvent()

  • keyPressEvent()

  • keyReleaseEvent() for processing keyboard input

KDisc (see Listings 4.10–4.12) demonstrates use of the mouseMoveEvent() and keyPressEvent(). The widget draws a disc on itself and lets the user move the disc around by dragging with the mouse or pressing one of the four arrow keys (see Figure 4.7).


Figure 4.7. The KDisc widget processes mouse-move events to let the user drag the disc around.



Example 4.10. kdisc.h Contains the Class Declaration for the KDisc Widget

   1 
   2 1: #ifndef __KDISC_H__
   3 2: #define __KDISC_H__
   4 3:
   5 4: #include <qwidget.h>
   6 5:
   7 6:
   8 7: /**
   9 8:  * KDisc
  10 9:  * Lets the user move a disc around with the mouse or keyboard.
  11 10:  **/
  12 11: class KDisc : public QWidget
  13 12: {
  14 13:  public:
  15 14:   KDisc (QWidget *parent, const char *name=0);
  16 15:
  17 16:    protected:
  18 17:     /**
  19 18:      * Disc the widget.
  20 19:      **/
  21 20:     void paintEvent (QPaintEvent *);
  22 21:
  23 22:     /**
  24 23:      * Draw the disc under the mouse cursor.
  25 24:      **/
  26 25:     void mouseMoveEvent (QMouseEvent *);
  27 26:
  28 27:     /**
  29 28:      * Examine the key pressed and move the disc accordingly.
  30 29:      **/
  31 30:     void keyPressEvent (QKeyEvent *);
  32 31:
  33 32:  private:
  34 33:     QPoint discposition;
  35 34:
  36 35: };
  37 36:
  38 37: #endif

The previous listing, Listing 4.10, shows the class definition for the KDisc widget. You will be processing paint events to draw the disc; mouse-move events to move the disc in response to a mouse drag; and key press events to move the disc when one of the four arrow keys is pressed. See Listing 4.11 for the code that accomplishes these tasks. The following two sections discuss the mouse events and key events, respectively.


Example 4.11. kdisc.cpp Contains the Class Definition for the KDisc Widget

   1 
   2 1: #include <qpainter.h>
   3 2:
   4 3: #include "kdisc.h"
   5 4:
   6 5: KDisc::KDisc (QWidget *parent, const char *name=0) :
   7 6:   QWidget (parent, name)
   8 7: {
   9 8:
  10 9:   discposition = QPoint (0, 0);
  11 10:   setMouseTracking (true);
  12 11: }
  13 12:
  14 13: void
  15 14: KDisc::paintEvent (QPaintEvent *)
  16 15: {
  17 16:   QPainter painter (this);
  18 17:
  19 18:   painter.setPen ( QPen (Qt::black, 3) );
  20 19:   painter.setBrush ( QBrush (Qt::blue, Qt::Dense4Pattern) );
  21 20:
  22 21:   painter.drawEllipse (discposition.x(), discposition.y(),
  23 22:                25, 25);
  24 23: }
  25 24:
  26 25: void
  27 26: KDisc::mouseMoveEvent (QMouseEvent *qmouseevent)
  28 27: {
  29 28: 
  30 29:   if (qmouseevent->state()==Qt::LeftButton)
  31 30:     {
  32 31:       discposition = qmouseevent->pos();
  33 32:       update();
  34 33:     }
  35 34:
  36 35: }
  37 36:
  38 37: void
  39 38: KDisc::keyPressEvent (QKeyEvent *qkeyevent)
  40 39: {
  41 40:
  42 41:   switch (qkeyevent->key())
  43 42:     {
  44 43:     case Qt::Key_Left:
  45 44:       discposition = QPoint ( discposition.x()-10,
  46 45:                   discposition.y() );
  47 46:       update();
  48 47:       break;
  49 48:     case Qt::Key_Right:
  50 49:       discposition = QPoint ( discposition.x()+10,
  51 50:                   discposition.y() );
  52 51:       update();
  53 52:       break;
  54 53:     case Qt::Key_Up:
  55 54:       discposition = QPoint ( discposition.x(),
  56 55:                   discposition.y()-10 );
  57 56:       update();
  58 57:       break;
  59 58:     case Qt::Key_Down:
  60 59:       discposition = QPoint ( discposition.x(),
  61 60:                   discposition.y()+10 );
  62 61:       update();
  63 62:       break;
  64 63:     default:
  65 64:       qkeyevent->ignore();
  66 65:     }
  67 66:
  68 67: }

4.4.1. Mouse Presses

In KXOSquare you processed a mouse click with mouseReleaseEvent(). The QMouseEvent::button() method tells which button was clicked. The reason you chose mouseReleaseEvent() and not mousePressEvent() is because you shouldn't consider a user's mouse click to be registered until the mouse button is released. This way, the user will have a chance to change his or her mind. This behavior is common practice. Try clicking pushbuttons on your screen. Notice that no action occurs until the mouse button is released.

In mouseMoveEvent() you test QMouseEvent::state(), not QMouseEvent::button() to check the state of the mouse. If the left button is being held down, the disc is moved so that it is centered under the mouse cursor (see line 31 of Listing 4.11):


   1 
   2   discposition = qmouseevent->pos();

Then update() is called to clear the widget, erase the disc, and call paintEvent() to redraw the disc in its new position.

In KDisc::KDisc (see line 10 of Listing 4.11) you call


   1 
   2   setMouseTracking (true);

This informs Qt that you want to receive mouse-move events. Because the mouse can move around quite a bit, this can generate lots of events. Generating and passing these events takes time; therefore, by default, they are not generated. For this widget, you need those events to make your UI function as you have designed it.

4.4.2. Keystrokes

QKeyEvent::key() returns a code telling which key was pressed. The constants, such as Qt::Key_Left, Qt::Key_Right, and so on, are defined in qnamespace.h. (qnamespace.h is included by qwindowdefs.h, which is, in turn, included by qwidget.h. Thus it is enough to include qwidget.h if you want to process keypresses.)

You call QKeyEvent::ignore() when you don't process the key press. This lets Qt know to pass the keystroke on to our parent widget.

Note

Don't return from a keystroke event handler without calling QKeyEvent::ignore() if you don't process the passed keystroke.

Next, in Listing 4.12, is a main() function that you can use to create an executable that creates and shows the widget.


Example 4.12. main.cpp Contains a main() Function Suitable for Testing KDisc

   1 
   2 1: #include <kapp.h>
   3 2:
   4 3: #include "kdisc.h"
   5 4:
   6 5: int
   7 6: main (int argc, char *argv[])
   8 7: {
   9 8:   KApplication kapplication (argc, argv, "kdisctest");
  10 9:   KDisc *kdisc = new KDisc (0);
  11 10:
  12 11:   kapplication.setMainWidget (kdisc);
  13 12:
  14 13:   kdisc->show();
  15 14:   return kapplication.exec();
  16 15: }