The K Desktop Environment

Next Previous Table of Contents

4. Event Handling

This chapter will illuminate some of the internals of KDE/Qt programming, and will dive into the fascinating subject of event handling as well. It is meant for people who feel they need deeper insight to the more advanced topics of Qt based programming. In particular the Signals and Slots mechanism is explained in detail. This because users have indicated that resources about the meaning and usage of signals and slots are somehow hard to find in other documentation. For non-english persons the translated version are available, offering easier access than the originals.

Event handling covers the communication of an application. Withn that, we mean the interaction between different objects and between objects and the user. Beginners in particular have a hard time to learn the mechanisms underlying event handling. Many of the misconstructions found in beginners' code can be attributed to a lack of understanding of the Qt signals and slots framework.

Signals and slots are formally not a part of event handling but are used during the event processing often and are a major reason why simple widget elements such as buttons can be usd in such a simple way.

4.1 Signals and Slots

This section covers the Qt concept of advanced object communication. In this context objects are the instances of classes that are created during runtime by the application. The instances normally don't know about each other, but they have to communicate to allow method calls of other object's methods. The usual way for XWindow has been using function pointers, but this lead to very complex code. It also gives no opportunity for the compiler to check types (a function pointer is actually just a (void*) pointer).

The Qt library offers a far better solution to this by a mechanism that is called signals and slots.

Before going into the technical details, I'll explain the mechanism by a comparison to everyday-life. Imagine you have a bunch of people somewhere and someone looks into the sky. He sees a balloon and points with his finger to the balloon and says: "Hey, there's a balloon !". Now, what do other people do that are standing around him ? One who is interested in balloons will look up as well and have a look at it, maybe take a picture with a camera. Others won't because they were never interested in balloons and don't want to know about it; they just ignore what was said.

With Signals and Slots, things are just the same, except that instead of people objects interact. Objects are instances of classes that can send out a signal in a certain situation. Objects which are interested in that kind of signal react to it, others do not. While humans have the choice to react interactively, class objects can't because they have no ears. But they can provide a kind of ears that listen to signals that were sent out. Then, those special kind of ears have to be connected to the signal an object emits to provide the medium to transmit the message to the receiver. Any kind of ears that could react won't if they are not connected with the signal and therefore ignore the message transmission.

I hope this made somehow clear how the signal/slot mechanism works generally. The chart shows this a bit more appropriate:


Person_1                            Person_2                       Person_3

signal balloon_seen();              slot i_see_it();               slot not_interested();

watch_out(){                        i_see_it(){                         
  if(balloon){                         look_where();
    emit balloon_seen();            }
  }
}

connect (Person_1, SIGNAL(balloon_seen()), Person_2, SLOT(i_see_it()));

This explains more about the functionality. The class that builds Person_1 provides a signal balloon_seen(). Also it has a method watch_out() that symbolizes that he watches for something. If this method detects that a balloon is there, it emits the signal and transmits the message to the outside of its responsibility. After the emit, Person_1 is not responsible for any actions that follow as a reaction to this signal; it just does the message invocation.

Now, the table contains the other persons Person_2 and Person_3. Both provide methods that are slots; Person_2 has one slot that is called i_see_it() and Person_3 a slot not_interested(). Those slots are just like any method with the difference that they can also be connected to a signal and build a receiver for the connection. They will execute the slot implementation when the object receives the signal message. In this case, we have a typical connection method at the last line. The connect() takes Person_1 as a signaler object. It connects the signal balloon_seen() that the object may send out when he sees a balloon with Person_2. Person_2 is then the receiver object. Now, the receiver has to do something with the signal; we have to tell him, which method to execute whenever Person_1 sees a balloon. The implementation of the slot i_see_it() just calls another method to make this example short. look_where can symbolize a method to localize the coordinates, the color, the size of the balloon or how many people the balloon carries.

Person_3 then is anther object. The class that builds it provides a slot as well, the method not_interested(). The implementation doesn't matter for our example here, because we don't want Person_3 to react to Person_1's detection of a balloon. We could, if we add another connect though, just with Person_3 instead of Person_2 and the according slot Person_3's class provides.

Requirements

This way of object communication is not provided by C++; it is a part of the Qt library.

If you want to use Signals and slots they have to be declared as such in the class-declaration for two good reasons:

  1. you know which signals and slots a class provides and the parameters they need
  2. the moc (Meta Object Compiler) of Qt can create the implementation for signals and slots automatically and include it to the compile process (since signals and slots are not part of the C++ standard, your C++ compiler wont do that)

Now, we're going into the details of the Qt library. To make use of the signal/slot mechanism, you have to:

Normally, KDE and Qt applications constructed with automake and autoconf (amongst them all programs made with KDevelop) already run moc when necessary. This is done by the program automoc, which also does everything needed to create the meta object implementation for signals and slots as well as incorporating the correct headers for the implementation and the inclusion into the build-process. So you don't have to take care of updating any moc output files after changing header file implementations nor about the integration of the moc source file output into the project. Those will be automatically generated by detection of the Q_OBJECT macro in the class declaration.

If you have further questions please read the page "Using The Meta Object Compiler" of you Qt Online Reference. It covers all restrictions on using signals and slots.

Emitting Signals

This part describes the several ways of signal emission. It is important to know where signals are emitted and for what purpose you would do so.

We separate two ways of signal usage, one which is the usual way through sub-classing QObject, and the other to use the QSignal class from within classes that don't want to inherit from QObject but want to use the signal emission features.

So, when deriving from QObject, we already said that we have to add the Q_OBJECT macro into the class declaration. Then any signal that a class object will emit has to be inserted in the class declaration with the modifier signals:

Example:


class Foo : public QObject{
  Q_OBJECT

public:
  Foo();

signals:
  void mySignal();
  void myParameterSignal(int, int);
};

This shows the insertion into the class declaration and also shows that you can use signals to emit values as well. This is one of the best features and is widely used throughout KDE and Qt.

Now, this shows one half of the work. The other is: where does the signal get emitted ? For this, you have to use the keyword emit in connection with the signal name and the transmitted actual parameters. The place where to emit is usually within a method that is processed and wants to inform about the state of the object by the signal to outside objects.

Comment

The keyword emit is technically only an empty #define, therefore the C++ -compiler only sees a normal method call. The moc takes care to add the according meta-object creation and initialization, which finally implements the signal as a member function in the moc output.

As an example, we have a look at a snippet of code where a method of KMyClass cuts out a part of a visible area the user works with:


void KMyClass::cut(){

  int xpos=view->xPos();
  int ypos=view->yPos();
  view->cut(xpos, ypos);

  emit cutting(xpos, ypos);
}

This method could be called e.g. from a toolbar icon "Cut" or the according menu entry of the application's menu bar. We assume that we have a view area that we retrieve as a pointer view. The class providing the view area offers cutting a selection by an x and y integer value. The actual values can be found out with xPos() and yPos() and stored into xpos and ypos to avoid temporaries and to reuse the values for emitting the signal. Then, we call the cutting method via the view object by the actual parameters. Finally, we want to inform about what's being done by emitting a signal cutting(). In case anyone needs to know about what happened, we have also included the exact information about where we have done the action by transmitting the values with the signal.

Another way to produce a signal is, as mentioned, possible without sub-classing QObject. Qt provides this by the class QSignal. The usage is rather simple, though inheritance of QObject should always be preferred.

To use QSignal, write a normal C++ class. Then add the following:

  1. #include <qsignal.h>
  2. add a QSignal member attribute to the class declaration
  3. add a method void connect(QObject* receiver, const char* member); to the class
  4. create the signal in the constructor with new
  5. destroy the signal in the destructor with delete
  6. implement the connect() method by calling connect(receiver, member) on the signal to emit
  7. emit the signal at any place in your class code with yoursignal->activate()

Slot Implementation

After explaining the ways of how to produce signals by objects, those can only be of important use if an application's classes provide slots that get connected with signals. The slots themselves are normal C++ class member functions and can therefore be called any place any time you need to, only depending on the class access rights. They just have an additional feature that they can be called automatically during runtime by their connected signals. The main difference is the declaration of the methods within the class:


class Foo : public QObject{
  Q_OBJECT

public:
  Foo();

public slots:
  void mySlot();
  void myParameterSlot(int, int);
};

Above, you see that the class Foo has two slots declared in the class-declaration. As the modifier is also preset, here to public, it follows that you can also restrict slot usage by access rights to public, protected and private. The only thing to watch out for is that all methods after public slots: are slots, so you have to start with public: again, if you want to add public methods behind the slots declarations. Whe connecting signals to slots, the sender can only connect to slots the receiver allows to call depending on the access rights e.g. a private slot cannot be called by an instance of another class than the own (which means only instances of the same class can connect signals to this slot).

Another restriction is the return type. As slots are most often called by signals, where should they deliver any return values ? Therefore, your slots will always have void as return type.

For all restrictions of implementing slots in classes, see the Qt online reference documentation, section The Meta Object Compiler.

Connections

The last section of this chapter deals with connecting signals and slots. As stated in the Signals section, there are two ways to produce signals, and in the Slots section we saw that slots are methods which have modifiers as well.

When it comes to connecting signals and slots, you generally will use the static method of QObject to send a signal to a method:

bool connect(const QObject* sender, const char* signal,
             const QObject* receiver, const char* member)
bool disconnect(const QObject* sender, const char* signal,
             const QObject * receiver, const char* member)

Both are static public members of QObject and can be called everywhere in the code if you want to connect/disconnect a sender and receiver by certain signals and slots. The signal in these methods have to be used with the SIGNAL() macro; the slot of the receiver has to be used with the macro SLOT().

Comment

Note: within classes that inherit QObject you don't have to use the static variant, so instead of using QObject::connect(), you can also use the overloaded methods that either the sender provides (such as QMenuData to connect activated() directly to the receiver's slot while inserting a menu entry) or just call connect() directly.

Further, the signal and slot should have the same parameter list as parameters are translated from the signal to the slot method. Slot implementations that don't require using any transmitted parameter only have to declare the type but do not need a formal parameter. This avoids the unused parameter warnings you usually get when declaring formal parameters which aren't processed in the method. The slot methods itself can also have less parameters than the signal emits.

Also, signals can be forwarded. This means, you can use the connect() method to connect two signals, meaning that the sender's signal will cause the receiver to emit the connected signal. If several slots are connected to one signal, the slots will be ececuted one after the other, in an arbitrary order, when the signal is emitted. (Qt documentation: metaobjects.html)

4.2 The Event Queue

The previous chapter dealt with the object communication by Qt's signal/slot mechanism and we know how an application can arrange a certain functionality. But we have not yet discussed the events produced by the user. Generally, he communicates with an application by the keyboard and the mouse. When running an application under XWindow, the X11 protocol ensures that the right application is called to process the events. Only the application object receives the event and can provide means to handle them. This is called event handling. The application object therefore has to keep an event queue when initialized where events run into and get processed to the right application window. The application itself is running in a so-called main event loop, which indicates that it waits for user interaction until the user quits the application either via the quit() slot or by calling exit(). The exit() function also returns the value to the main() function's call of exec() to terminate. If the number exit() is called with is higher than 0, an error has occurred. The exec() function call in main() starts the event handling.

X11 event handling starts by defining the events the window is willing to process. All other events are already filtered out. The events which are selected, go into the event queue and wait to be processed. Typical events include the XExposeEvent, XDestroyWindowEvent and XResizeRequestEvent. All these events have to be handled by the application. Fortunately (for you) Qt takes care of most of the event processing. This is done using the QEvent class; the Qt event abstraction.

This QEvent is then processed by QApplication's notify() function. This sends all receivers which are derived from QObject and are part of the application the according event with receiver->event(QEvent* event). The application objects therefore get notified about any event that happened and can process the event via the re-implemented event() method of QObject if needed. QObject also allows a self-created event filter functionality by installing an event filter on the class. The event filter is processed first if one is installed and then the event method returns control over the event if the event filter returned false. If the event() method doesn't find any event processing, it returns false and the application gets to know that the object didn't sign responsible for the event. If the event was successfully processed and the event() returns true, the event is deleted from the event queue.

Processing Events

Qt and KDE applications use a graphical interface to make themselves visible to the user. Application windows are deived from QWidget, the baseclass for any graphical object drawn in windows. Independent of how the widget is created, the application object notices all widgets that are created and keeps a list of these. Furthermore, the windows can have several states dependent on how they are created.

The QWidget class is most important to understand because it re-implements the event() method already to transform the incoming event to some commonly occurring events, e.g. a mouse event, and creates appropriate filter event functions which are easier to re-implement for the special purpose a widget may need. This is e.g. used for any widget that inherits the QWidget class, because those events can be used to send out signals that are avoiding any sub-classing of common widgets such as pushbuttons. The pressed() signal e.g. is emitted on the re-implementation of QWidget's mousePressEvent(), showing that you don't have to subclass a simple pushbutton to find out the event and to get notified that the user pressed it.

Re-implementing these methods is one of the common tasks of a programmer writing his own widgets, therefore you will have to know about the virtual event functions of QWidget and the event queue processing very well.

Above, we mentioned that a widget can have several states. This predefines the behavior of the widget towards the user as well as towards the application object.

A widget can be:

  1. a main widget when set as the main widget with QApplication's setMainWidget() or KApplication's setTopWidget.
  2. a top widget when the parent of the widget is 0.
  3. a modal widget usually a QDialog which has its own event loop
  4. a semimodal widget like a QDialog, but without its own event loop
  5. a popup widget when the widget flag is set to WType_Popup, is also a top widget

The specialized behavior of the widgets depending on their creation is then:

  1. main widget: a main widget is the most important widget of the application, but the application doesn't need to have a main widget of course. If it has, and the main widget gets closed, the application terminates automatically by calling quit(). The QApplication method mainWidget() returns the pointer to the main widget.
  2. top widget: a top widget is a widget which has no parent. All widgets that have non-zero parents are sub-widgets of the parent. The list of top level widgets can be found with QApplication::topLevelWidgets(). If an application doesn't have a main widget but only top widgets, connect quit() to QApplication::lastWindowClosed() to terminate the application, otherwise the application object will still exist even if all windows are closed. The application finds the currently active (focus enabled) widget with QApplication::focusWidget().
  3. modal widget: a modal widget is a widget derived from QDialog. QDialog widgets have their own local event loop which is entered when calling exec() on the dialog object. The dialog is modal, if the third widget flag is set to true, meaning that the dialog has to be terminated before the event processing can return to other application windows. All events are sent to the dialog by the application object. The current modal widget is found by the application by QApplication::activeModalWidget().
  4. semimodal widget: is a widget that disables events to other widgets like a modal dialog but does not have its own event loop. The modal flag has to be set to true like for a QDialog, although the semimodal dialog is derived from QWidget.
  5. popup widget: a popup widget is a popup that, when it appears, makes the application object send all events to it. The popup has to be finished before the event returns to any other widget, except for another popup. The current popup widget is found by the application object by QApplication::activePopupWidget() to post the events to.

The application object itself keeps track of all widgets that it is responsible for. The list of widgets can be retrieved by QApplication::allWidgets().

Summary: The application object is responsible for retrieving the events that were invoked by the user from the underlying window system. Then it converts these events via QEvent and can sent the event to any widget that is currently active. The widget itself is responsible to process the event either by accepting the event after finding out that it has an event-handler (or to be precise: the event handler has to return true to the notifying of the application's event posting). The event is deleted from the queue if an event handler was found, if all possible event handlers return false, the application is not responsible for the event and the event is ignored (deleted from the queue as well).

What is left to explain about event processing is the installation of own event filters for widgets or any other object derived from QObject and the way QWidget contains a pre-defined event handling that has to be overwritten for processing events on custom widgets. Mind that as a guideline to define own event handling, you should reimplement QObject::event() for all classes that do not inherit QWidget and the more specialized event handlers described below for all QWidget inherited classes. Also, preserve the declarations as virtual protected to ensure reusability and consistency for your code.

Event Types

The events sent to the application are, as described, converted by QEvent to Qt events. The event type can be found out by using the type() method of QEvent, which can then be compared with the event that you want to know about. Now, the event type that type() delivers is an integer number; those are declared with #define in the file qevent.h.

Qt 2.0 uses an enum for all available event-types whose entries are similar to the current defines but generally leave out the Event_ prefix. The event type can be retrieved as described above, so you only have to change the comparison of the event type.
After filtering events for the specialized event class, more information can be found out by explicit conversion to the event class to retrieve exact data about the event.

Example:


bool MyClass::event( QEvent* event ){

  if( event->type() == Event_MouseButtonPress){
    if( (QMouseEvent*)event->button() == RightButton ){
      // do something with the event, eg. pop up a contextmenu
      return true;
    }
    else{
      return false;
    }
  }
  else return false;
}

The event has been explicitely converted to QMouseEvent* here to find out the button type. You could also find out the position of the mouse pointer at the time of the event, see the following section about mouse events

As there are so many event types that can occur, I have sorted the events defined in qevent.h logically according to the general event type and the subclasses that provide an event handling and offer the exact information about specific events. The sorting contains:

This will allow you to logically have a look at what might be interesting to reimplement or use before having to browse the Qt online documentation in depth.

Window Events

By window events, all events that are produced by the window system in regards to handling any visible part of the application windows. This does also include the event processing in the other direction, because by methods like QWidget::close() or QWidget::repaint() events are sent to the window system to execute a synthetic events to manipulate the window behavior (either inside the window or affecting the whole window).

This is sometimes a bit hard to understand, so I will give another short example here. Assuming you have an application that has a window on the desktop. This window can be manipulated by the user through actions like:

These are incoming events that are sent to the application. The event type is determined by QWidget's event() re-implementation and converted to the according event class that provides methods to handle the event specifically. Now, when you have a look at the QWidget class, a lot of methods are provided for window manipulation, e.g. resize(). You're using these methods, but you probably never thought about their way of execution. In effect, these methods work the other way round: they produce an event that is sent to the display by qt_ functions to execute actions like simulating a user action. This way, events can also be produced to gain synthetic events ( see below ).

Within a window, the widgets are arranged somehow. As each widget is treated like a separate window internally (it always is a QWidget or inherits it), the same events can be processed randomly inside the window for incoming events as well as manipulating internal parts of a window.

The following chart shows the according event classes with the event types they process:

Qt 2.0 includes another event class QWheelEvent to handle events that occur by wheel-mice. The QWidget class also provides an already existing event handler for this, wheelEvent(QWheelEvent*). Also all drag'n drop events have their event-handlers already in QWidget, see the notes for drag'n drop

Focus Events

Focus events are somehow special to windows, but I have added a separate section for those due to the filtering of focus events in QWidget. A focus event is generally the fact that a window consists of several widgets who have a focus policy, which means that there can only be one widget at a time that can have the current input focus. The focus itself can be activated by a mouse click to activate the clicked widget or pressing the TAB key to forward the focus to the next widget in the tabring focus. Backwards focus setting can be done with SHIFT+TAB. This is a common usability and users expect windows to have this behavior so they can navigate the focus to the next widget. A good example for this is a dialog. If the dialog is a modal widget, it has to be finished first, otherwise is active when it gets the focus if it is the active window. Now, on dialogs widgets can be disabled as well to prohibit any user input. These disabled widgets don't get the focus either and are painted disabled.

The QWidget class defines the focus handling already when receiving an event. If the event type is Event_FocusIn, the widget gets the keyboard focus by event()'s conversion into a QFocusEvent.

This already catches a key event of the keys TAB and the combination SHIFT+TAB without processing these keys to QKeyEvent if there is a widget the focus can be forwarded to. Anyway, you can influence this filtering by setting focus policy. The focus policy can be set to:

The QFocusEvent class delivers information about the focus event by comparing the event type with type(). The method gotFocus() returns true on Event_FocusIn and lostFocus() returns true on Event_FocusOut. The QWidget predefined event handlers are:

  • focusInEvent(QFocusEvent*) for Event_FocusIn
  • focusOutEvent(QFocusEvent*) for Event_FocusOut
  • You have a lot of choices to influence the default focus handling by the methods provided by QWidget, e.g. you can forward the focus to another widget with setting another focus order. Mind that the focus is arranged in a ring and your implementation of this manipulation should take care that it doesn't break the focus handling. The default focus ring depends on the declaration of your widgets while constructing; if your tests result in a fuzzy focus order you have to recheck the declaration. The default design should always be left to right and top to bottom for forwarding the tab-focus. When using the geometry layout management you should declare your widget order first and then implement the layout.

    Hint: if your widgets use multilineedits, the user expects the tab key to produce a tab in the text, not the forwarding of the focus. Therefore a simple method is to use setFocusPolicy(NoFocus) or setFocusPolicy(ClickFocus)on all additional widgets that are in the current window. Menubars and Toolbars do not have the tabfocus by default, so you don't have to set the focus policy there. An exception is the QWhatsThis button, which although mostly used in a toolbar, receives the input focus on TAB.

    Mouse Events

    Mouse events are, as the word says, generated by the user's handling of the mouse. As these will only be of interest if the mouse is over a widget, the best use to process mouse events is to reimplement the virtual methods QWidget provides for this. Now, the window system sends the following event types to the application by mouse actions:

  • Event_MouseButtonPress
  • Event_MouseButtonRelease
  • Event_MouseButtonDblClick
  • Event_MouseMove
  • This means, that the user can handle the mouse with moving the cursor in X and Y direction, press any button and release it. A button can also be doubleclicked, which is a special event and requires special handling. As the event message is filtered by the event() method of QWidget, these event types are converted from a QEvent to a QMouseEvent. Then, the mouse event is processed, whereby QWidget provides a set of event handlers already. What is interesting about a mouse event is not only the type, but the other parameters, as mentioned, to implement certain actions on specific events. One of the most recently used event types are probably a right button press over a widget to open a context menu to allow quick access to commands that are available. This requires the exact position of the event's occurrence and a comparison of the button type. Double clicks are processed by the user as producing a mouse press event followed by a mouse release event and another mouse press event. As the time between the release and the next press cannot be easily determined, the QApplication class has methods to define the click time which is by default 400 milliseconds: QApplication::setDoubleClickInterval(int ms) is what you need.

    The QMouseEvent class allows finding out the exact event by providing information about: Button type: using button()

  • NoButton
  • LeftButton
  • RightButton
  • MidButton
  • Mouse Position:

  • pos() : relative mouse position within the widget (x,y)
  • globalPos() : absolute mouse position on the desktop (x,y)
  • globalX() : global x position of the mouse pointer from left to right
  • globalY() : global y position of the mouse pointer from top to bottom
  • x(): relative mouse position within the widget from left to right
  • y(): relative mouse position within the widget from top to bottom
  • Additional Keyboard presses at the same time: using state() and OR'ed with Left,Right and MidButton

  • ShiftButton
  • ControlButton
  • AltButton
  • The provided event handlers are:

    Thereby, the mouseDoubleClickEvent() by default only produces a mousePressEvent. You have to reimplement the mouseDoubleClickEvent() to receive the event and process it as it is produced as an hypothetic event, not produced by the window system under X11. Set the double click time with QApplication::setDoubleClickInterval().

    For MouseMove events, you have to watch that the mouse event is only handled if a button is pressed. This can be configured by QWidget::setMouseTracking(true) to receive all mouse movements as QMouseEvents in the event handler. The implementation therefore is on QWidget: the event is raised, event() asks if mousetracking is set to true. If not (default), the event is ignored, if yes, the event is converted to a QMouseEvent and delivered to the mouseMoveEvent() event handler.

    Additionally, the widget can detect if the mouse enters the widget's space. This is done by filtering out the mouse movement before generating the QMouseEvent in QWidget::event():

    An example for reimplementing an enter and leave event is QToolButton. The buttons in the toolbar have a automatic raising behavior in windows style, therefore the widget uses an enter event to raise the button in 3D and lowers it when the mouse leaves the widget area.

    Wheel mice are offering an additional functionality for scrolling by the wheel. Qt 2.0 offers solutions for handling wheel events in a separate event class QWheelEvent, therefore these are not handled as mouse-events.

    Keyboard Events

    A keyboard event is generally sent to the application if the user pressed or released a keyboard button, therefore can determine the event by:

  • Event_KeyPress
  • Event_KeyRelease
  • Handling

    Now, the QWidget class converts a keyboard event from QEvent to a QKeyEvent if the widget has the keyboard input focus; if the widget has tabfocus policy, the TAB and SHIFT+TAB key-presses are filtered out to produce a QFocusEvent instead a QKeyEvent. The QKeyEvent class provides more convenient methods to process the key event. Those have some specialties which I want to discuss.

    Event Handlers:

    QWidget provides two event handlers for the two event types the keyboard produces:

  • virtual void keyPressEvent(QKeyEvent*) for Event_KeyPress
  • virtual void keyReleaseEvent(QKeyEvent*) for Event_KeyRelease
  • Acceptance:

    The widget that receives a QKeyEvent and re-implements the event handlers from QWidget has to determine if it wants to accept or ignore the keyevent, so the widget can sent it back to the parent widget. Therefore you have to know that the accept flag is set to true in the constructor of a QKeyEvent. You can clear this flag with calling ignore() if you don't want to process the key and sent it back.

    Modifiers

    The user can press so-called key-modifiers. Those are the ShiftButton, ControlButton and AltButton. The currently pressed modifier keys can be found out with state(), which returns the modifiers OR'ed together.

    Key Values

    The key values for all keyboard keys are defined in the include file qkeycode.h.

    Qt 2.0 has all keycodes coded into namespaces of the class Qt located in qnamespace.h, enum keys.
    The key that produced the event can be retrieved with key() and then compared to the defined keycode. The ASCII value can be found with ascii(). Mind that the symbolic constants for key values are platform independent and allow the best usage as they are simple to remind.

    Keyboard Accelerator Questions

    A question that often occurs is the implementation of keyboard accelerators. As this handbook primarily targets KDE programming, I will go into that as well.

    Qt has a class QAccel which offers connections of key presses with actions. This is done by installing an event filter that filters out keyboard events that match any item inserted into the QAccel object. The keyboard accelerator itself has to be a combination of the CTRL, SHIFT or ALT keys with a normal keyboard key. Another value can be ASCII_ACCEL here to use the ASCII keyboard value for the accelerator.

    An accelerator instance is then created by using the widget that it should work for as an event filter with the widget as its parent. Insert the keys with insertItem(keycode, ID ). Although setting the ID is not necessary, you should write yourself a logical ID table containing integer value defines that allow using the ID later to find the accelerator item and helps keeping an overview over the used numbers.

    Then, the item has to be connected to the object and slot it shall work for on its signal activated(int ID) using the connectItem() method instead of the usual QObject::connect() variant.

    Popup menus (only within menu-bars) already provide accelerator usage without explicitely creating a QAccel instance. You only have to use setAccel() there; see QMenuData for more details.

    Now, when it comes to KDE, things will be a bit different because KDE offers some additional features. First of all, you have to use the class KAccel instead of QAccel; the usage is almost the same. The KAccel class (part of kdecore) also offers an insertion into menus and configuration of accelerator keys, which then can change the menu entry as well.

    Further, KDE provides globally configured accelerators for standard keys.Those are defined in kaccel.h and only have to be inserted. The class documentation also shows the usage of standard accelerators and accelerators in general by examples.

    Whenever an application offers keyboard accelerators, users often feel uncomfortable with the given values and want to change them themselves. Also, the programmer usually sets keyboard accelerators for those slots that he thinks are the most needed functions in his program; in fact he should in any case add accelerators to all of his available menu entries and functions. Further, KDE has two ways to offer configurating the KAccel object as well as saving the configuration to the application config file by providing a ready-to use dialog for configuration as well as a widget that can be used within a custom configuration dialog (most often a tab dialog) to configure the keys.

    For accelerator configuration dialogs, see section Keyboard Accelerators.

    Drag'n Drop Events

    One of the most advanced techniques to allow application communication is drag'n drop. This offers users a cool and fast feature to handle the objects they work with in an application by an intuitive interface, catching it by a symbolic icon or by marking parts of a document and move the dragged object away from the current area. The area the dragged object comes from is therefore called a dragsource. Then the user moves the object away to another area of the application, to the desktop or into the area of another application. After releasing the mouse button over there, he expects the data dragged to be dropped into the drop area. Therefore the drop area is also called a drop site or a drop sink. The window system provides a protocol for this, the XDND protocol, which causes the emission of the according events. The application windows can support these events by providing methods to drag object out of the window and methods to accept a drop event. Qt implements this by a class QDropSite.

    Qt 2.0 makes this a lot easier. QWidget already contains all event handlers that are mentionend here for the class QDropSite, therefore you only have to remove the inheritance from QDropSite of your drag'n drop enabled widget and add a call to setAcceptDrops(TRUE) in the widget's constructor.
    The widget that wants to use drag'n drop has to inherit this class additionally to the base widget class. Then, the QDropSite offers additional event handlers that convert the QEvent types for drag'n drop to one of the according specialized event classes. The programmer also has to take care in his re-implementation of the mouse event handlers by which mouse button holding a drag can occur. Also, Qt currently provides two types of data to decode, text and images, which should be the most common usage. The following chart contains the window system events, the event classes handling these events and the event handlers of QDropSite:

    The event handlers are all implemented as public and reimplementations should preserve to

    Note: the system event Event_DragResponse is automatically handled by the application object internally through the Qt implementation. It causes a QDragResponseEvent that accepts/rejects the drag action.

    Comment

    KDE also contains another implementation of Drag'n Drop functionality. The description of using KDE 1.x Drag'n Drop has been left out because this will be removed in KDE 2 and only the Qt implementation is going to be used with an extended implementation of the XDND protocol.

    Comment

    There exists a zoo of DND protocols. At the moment of writing, the Qt DND protocol does not support the Motif DND protocol (as used by for instance Netscape and GNOME). Please be aware of this if you reimplement the Qt DND functions.

    4.3 QWidget Virtual Methods

    As the event handling generally is implemented by virtual protected methods, especially the event() method provided by QObject, the QWidget class reimplements this function in order to sort out the incoming event and convert it to other event types that can be handled by more specialized classes. Furthermore, it calls the provided additional virtual methods by default implementations. The programmer has a good advantage by this pre-selection of events as the widgets he creates are all derived from QWidget and therefore will need one or more special event handler implementation. The most common events that are processed are mouse events and for text input mostly keyboard events. The other events mostly deal with focus handling, which moves on the keyboard input focus from one widget to the next. Programmers need to know about focus handling well, because the user will expect a certain behavior over his widget when using the TAB key and the SHIFT+TAB combination to move the input focus forward.

    Like explained in the Event Queue chapter, the QApplication takes care of converting window system events to objects of the QEvent class that are handled by the QObject::event() method. Therefore all classes that are derived from QObject can process event handling. The class QWidget already contains an overwritten event() method. It first checks for installed event filters (which are additionally created event filters by the programmer to redefine the default behavior by processing the event themselves or only the wanted events). Then it decides by the type() of the event which kind of event was called and converts it to one of the following event classes derived from QEvent who are delivered to the according virtual methods:

    Additionally, two events are called that don't match any other event type but may be important sometimes:

    virtual void enterEvent ( QEvent * ): the mouse enters the widget space

    virtual void leaveEvent ( QEvent * ): the mouse leaves the widget space

    Reimplementing is always needed if your custom widget wants to process the event and react to it. The reason why the event gets split up to other QEvent types is that the other event classes provide methods that are suitable to directly retrieving the needed event-specific data. This means, that e.g. a QMouseEvent can be asked for the button that caused the event or was active at that particular event as well as the global and relative mouse position where the event occurred. Mouse events are always used to pop up context menus over widgets which need to know the button (right mousebutton) and the position, because the user expects the context menu to pop up at the same position the mouse cursor currently is.

    The paint event is often needed if a widget has to draw something. Instead of creating a synthetic event (a logical event caused by the program internally), call repaint() here.

    4.4 Event Filters

    In addition to the normal processing of the event queue that is provided by the application object, the programmer can influence the default behavior by installing event filters. As explained above, all QObject inherited classes use event processing through the event() method. Instead of writing a completely new event handler in situations where you only need some events processed by your own methods, you should write an event filter. The event filter gets installed where you like to and filters out the event directly when QObject::event() is called internally.

    To write an event filter, your class has to overwrite the QObject::eventFilter() method and call installEventFilter() as well as removeEventFilter(). The declaration of these methods in QObject are:

    bool QObject::eventFilter ( QObject *, QEvent * ) [virtual]
    void QObject::installEventFilter ( const QObject * obj )
    void QObject::removeEventFilter ( const QObject * obj )
    

    The implementation of an event filter can be done in several ways. One that is possible is to create a new class for special event filters and create an instance of this class in the program. Then you can install the event filter on every instance you like to to achieve the same event filter on all instances independent of their class as well as redefining event processing of existing classes without inheriting them.

    An example would be:

    // Classdeclaration
    
    class KMyAppFilter: public QObject
    {
    protected:
      virtual bool eventFilter(QObject* object, QEvent* event);
    };
    
    // Filterimplementation
    
    bool KMyAppFilter::eventFilter(QObject* object, QEvent* event){
    
      if(event->type() == [the eventtype you like to filter])
      {
        [your filter implementation]
        return true;  // the event has been caught and processed
      }
      else
      {
        return false; // return false to continue processing the event with QObject::event()
      }
    }
    
    // installing the filter
    
    QObject* myfilter= new KMyAppFilter();
    QPushButton* mybutton= new QPushButton();
    
    mybutton->installEventFilter(myfilter);
    

    Another solution would be to reimplement the eventFilter() method in your inherited class as long as the base class is QObject, e.g. if your view area of your application wants to process a certain event that is not covered by the virtual methods QWidget provides. Then you have to install the event filter at the place you like to; normally this would be in the constructor of your class. With removeEventFilter() you can stop the event filter from processing the events any time.

    Comment

    Note: KApplication already has a global application event filter installed to filter out CTRL+ALT+F12 for KDebug

    4.5 Synthetic Events

    Before describing what synthetic events are and how they can be used by the programmer, I want to review the last sections briefly.

    We saw that the application object receives the window system events, processes them and creates event objects from the classes the library provides. The converted event can then be handled by event handlers that are specialized on the event class to retrieve further information about the event. Finally, we can influence the event handling itself by installing event filters and overwriting provided event handlers.

    This does the "normal" job of an application to execute actions according to user invoked events. On the other side, this system offers another possibility: the fact that the events are converted to class instances can be reversed - a so-called synthetic event can be created which fakes an original window system event. The next advantage is that these events are independent of the underlying window system.

    A good possibility where this feature could be used would be e.g. for learning programs. Those are almost non-existent for Unix but could offer a market to teach beginners how to handle programs similar to commercial products already available on other platforms. Also this could be a part of a help-system which an application can provide.

    An example description how to implement this:

    Provide a help window with a button that invokes a step e.g. "Show me". On pressing the button, the cursor will move to the desired location, e.g. to a pushbutton on the screen. The implementation then has to find out the exact position of the button and calculate the center coordinates the mouse pointer has to move to. Then the mouse pointer could move there by construction of a QCursor and using setPos(). The start position can be found out in the mouse event that called the function. Then, the cursor has to move visually by using setPos() in a loop where a QTimer could be used to run between positions to slow down the move so that the user can follow the mouse pointer.

    Creating Events

    Now, to come to the actual implementation of a synthetic event, you have to know the event you want to create. Therefore, you need the constructor parameters for the event classes. The following list contains the constructors including the event-classes hierarchy:

    QEvent(int type)

    type is one of the events declared in qevent.h

    Qt 2.0 uses all events from an enum instead of the #defines. See QEvent. The types are almost the same except they leave out the Event_ prefix.

    QCloseEvent()

    takes no parameter. Mind that the accept flag is set to false

    QFocusEvent(int type)

    type is either Event_FocusIn or Event_FocusOut.

    QKeyEvent(int type, int key, int ascii, int state)

    takes Event_KeyPress and Event_KeyRelease as type. key is one of the keys defined in qkeycode.h. state is ShiftButton, ControlButton, AltButton OR'ed.

    QMouseEvent (int type, const QPoint & pos, int button, int state)

    The type parameter must be Event_MouseButtonPress, Event_MouseButtonRelease, Event_MouseButtonDblClick or Event_MouseMove. The button is LeftButton, RightButton, MidButton, NoButton. state is ShiftButton, ControlButton and AltButton OR'ed for event Event_MouseButtonRelease, for events Event_MouseButtonPress, Event_MouseButtonDblClick state includes LeftButton, RightButton, MidButton.

    QMoveEvent(const QPoint & pos, const QPoint & oldPos)

    pos is the new position the widget shall move to, oldPos the old position. Retrieve the old position before creating the event with QWidget::pos().

    QPaintEvent(const QRect & paintRect)

    raise a paint event to repaint the area paintRect

    QResizeEvent(const QSize & size, const QSize & oldSize)

    resizes the widget from oldSize to size. Retrieve the old size before creating the event with QWidget::size().

    An example on how to create an event would be:

    QMouseEvent press_quit(Event_MouseButtonPress,
                           quit_button->pos(), LeftButton, LeftButton);
    

    This creates a mousePressEvent() for the widget quit_button with the left button.

    Sending Events

    After creation, the event has to be sent to the application instance to call its execution. Thereby, two ways can be used: one that directly processes the event and one that will place the event in the event queue at the last position:

    Direct execution:

    QApplication::sendEvent(quit_button, &press_quit);
    
    The sendEvent() waits for the result and returns true or false depending if the event has been accepted or not.

    Placement into event queue:

    QApplication::postEvent(quit_button, &press_quit);
    

    Comment

    The event for postEvent() must be allocated on the heap as it gets deleted immediately after the posing.

    To turn a posted event into a send event, use sendPostedEvents(QObject * receiver, int event_type). This requires the options given at the constructor. As you may see, some constructors don't need an event type, therefore the according event type can be found in Event Types but is also simple to guess as they are only responsible for one event type. Example: QCloseEvent only takes Event_Close, QPaintEvent only takes Event_Paint.

    4.6 Event Precedence

    In relation to influence the event behavior of the application, the programmer often faces situations where long operations block the Event_Paint and lead to a scrambled look of the application windows. These situations can be solved either by using a progressdialog that indicates the operation progress or by event precedence. This means that the current event gets stopped and the event queue is processed. The class QApplication offers a solution for this by two methods which are identical except the parameters. One is processEvents(), which processes pending events for 3 seconds or until there are no more events in the event queue. The other, more likely used method is processEvents(int maxtime), where maxtime is the time in milliseconds during which pending events can be processed.

    On one hand this means stopping the current long operation which then would take even longer to get finished if pending events are in the queue, but the user cares more about the visible state of an application than if an operation which takes some time will take a second longer (or even parts of a second).

    KDE offers an additional library for I/O operations in the upcoming KDE 2, which is under development. This will allow running the long I/O operations outside the application's process as multi-threading is not supported by Qt directly.

    4.7 Summary

    After this long chapter about signals, slots and events, I want to append a short summary so you can recapitulate the collected knowledge about application behavior.

    Further, we saw that the programmer can influence the behavior by:

    Finally, I hope this has given at least experienced C++ programmers a good insight and explanation on how Qt and KDE work. I have collected the information by working myself into the class structure and I hope that this collection makes it a lot easier for other programmers to get started especially in the advanced chapters of application design and programming. The information value is therefore not granted to be exact; if you may find any misconcepted or incorrect information, please contact me via email.

    Next Previous Table of Contents