• Aucun résultat trouvé

Handling Events

Dans le document Qt 4 THE BOOK of THE BOOK of (Page 188-192)

Events, Drag and Drop, and the Clipboard

7.2 Handling Events

We will implement a widget that displays the clock time in the local display format and the current date, also in the appropriate format, alternating every ten seconds (Figure 7.1 on page 189). The display itself should update every second.

7.2.1 Using Specialized Event Handlers

We implement the clock in a class called ClockWidget, which we derive from Q-LCDNumber, a Qt class that provides an imitation of an LCD display:

// clockwidget/clockwidget.h

#ifndef CLOCKWIDGET_H

#define CLOCKWIDGET_H

#include <QLCDNumber>

1 You can usethreadsto avoid blocking. We will discuss this in Chapter 12.

class QTimerEvent;

class ClockWidget : public QLCDNumber {

Q_OBJECT public:

ClockWidget(QWidget *parent = 0);

protected:

void timerEvent(QTimerEvent *e);

private:

int updateTimer, switchTimer;

bool showClock;

};

#endif // CLOCKWIDGET_H

Here we are particularly interested in, besides the constructor, the specialized event handler timerEvent(), which will update the clock time. In the updateTimer and switchTimer member variables we save numbers that serve as identifiers for the timers. The showClock status flag determines whether the clock time (showClock=

true) or the date (showClock=false) appears on the widget.

The implementation in clockwidget.cpp begins by specifying the form of the dis-play. Usually QLCDNumber shows a frame around the digital disdis-play. This behavior, inherited from QFrame, is disabled by the QFrame::NoFrame frame style. In addi-tion we dissuade the widget from drawing the LCD elements with shadows and a border, by passing on QLCDNumber::Flat to the widget’s setSegmentStyle() method.

// clockwidget/clockwidget.cpp

#include <QtGui>

#include "clockwidget.h"

ClockWidget::ClockWidget(QWidget *parent) : QLCDNumber(parent), showClock(true) {

setFrameShape(QFrame::NoFrame);

setSegmentStyle(QLCDNumber::Flat);

updateTimer = startTimer(1000);

switchTimer = startTimer(10000);

QTimerEvent *e = new QTimerEvent(updateTimer);

QCoreApplication::postEvent(this, e);

}

Now we need two timers. Each QObject can start a timer using the startTimer() method. As an argument startTimer() expects the number of seconds that must

pass before it triggers a QTimerEvent, which is addressed to the current widget.

Each QTimerEvent in turn contains an identification number, which is returned by the invocation of startTimer() that originates it. We can use this to distinguish between the two timers in timerEvent() later on.

So that we do not have to wait for a second to elapse before the time appears on the widget’s display, we manually send a timer event with the ID of the update-Timer, using the postEvent() method of QCoreApplication. As the target we specify the current widget (in this case, this) as we do later on for the events generated by the timers themselves.

In the timerEvent() method we first check whether the pointer to the event really is valid—just to be on the safe side. Next, if the event contains the switchTimer ID, this only toggles the showClock variable. The actual work awaits in the last conditional statement, which is triggered by an event containing the updateTimer ID.

if (e->timerId() == updateTimer) { if (showClock) {

If the widget is supposed to display the time, then we first determine the current time. In Qt, the QTime class is responsible for handling time. The currentTime() static method of this provides the current system time in a QTime object. This time is converted by toString() into a QString. Qt::LocalDate instructs the method to take into account the country settings (locales)of the user. Finally we must inform the display how many LCD digit positions are required. We deduce this from the string length and display the string with display().

Figure 7.1:

OurClockWidget alternately displays the time (above) and the date (below).

Although QLCDNumber cannot display all alphanumerical characters, it does cope with all the characters required for the date and clock time (0–9, slash, colon, and dot). setNumDigits(), by the way, does not change the size of the widget, the text just gets smaller, the more numbers there are.

On the other hand, if showClock is set to false, which means that the widget should display just the date, we proceed in the same way with the QDate class, which in Qt is responsible for managing date specifications, and whose API corresponds almost exactly to that of QTime.

Now we can try out our widgets with the following test program (Figure 7.1 shows the result in the form of two screenshots recorded at an interval of ten seconds):

// clockwidget/main.cpp

#include <QtGui>

#include "clockwidget.h"

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

QApplication app(argc, argv);

ClockWidget w;

w.show();

return app.exec();

}

7.2.2 Using the General Event Handler

Instead of treating the timer event specifically, we could also use the general event() event handler. Since this receives all types of events and we are only inter-ested in timer events, we must first check the event type. Furthermore, in order to access the timerId() method of a timer event, a cast to QTimerEvent is necessary:

bool ClockWidget::event(QEvent *e) {

if (!e) return;

if (e->type() == QEvent::Timer) {

QTimerEvent *te = static_cast<QTimerEvent*>(e);

if (te->timerId() == switchTimer) { showClock = !showClock;

return true;

}

if (te->timerId() == updateTimer) { // handle event timer as before ...

return true;

} }

return QObject::event(e);

}

Otherwise, we work with the te variable in the same manner as in the timerEvent() method (see page 188). One peculiarity is that event(), in contrast to the specialized event handlers, returns a Boolean value. This reveals whether an event has been processed or not.

If we override the default event(), we must not forget to forward all events that we donothandle to the event() method of the parent class. Otherwise, the event() method of the parent class would never be called and the event handling of our class would be lastingly disrupted. By calling QObject::event() unconditionally in the end, we avoid a broken event handling.

Thus, whenever there is an appropriate specialized event handler, you should over-ride it, rather than implement a general event handler. There is no need for a cast because the input parameter is already of the correct event type, and no need to forward unhandled events. In this way it can also be seen from just a glance at the class declaration which event handlers are implemented by the class.

Dans le document Qt 4 THE BOOK of THE BOOK of (Page 188-192)