Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Classes principales  ·  Annotées  ·  Classes groupées  ·  Modules  ·  Fonctions  · 

Mouse Calibration Example

Files:

The Mouse Calibration example demonstrates how to write a simple program using the mechanisms provided by the QWSMouseHandler class to calibrate the mouse handler.

Calibration is the process of mapping between physical (i.e. device) coordinates and logical coordinates.

The example consists of two classes in addition to the main program:

  • Calibration is a dialog widget that retrieves the device coordinates.
  • ScribbleWidget is a minimal drawing program used to let the user test the new mouse settings.

First we will review the main program, then we will take a look at the Calibration class. The ScribbleWidget class is only a help tool in this context, and will not be covered here.

The Main Program

The program starts by presenting a message box informing the user of what is going to happen:

    int main(int argc, char **argv)
    {
        QApplication app(argc, argv, QApplication::GuiServer);

        if (!QWSServer::mouseHandler())
            qFatal("No mouse handler installed");

        {
            QMessageBox message;
            message.setText("<p>Please press once at each of the marks "
                            "shown in the next screen.</p>"
                            "<p>This messagebox will timout after 10 seconds "
                            "if you are unable to close it.</p>");
            QTimer::singleShot(10 * 1000, &message, SLOT(accept()));
            message.exec();
        }

The QMessageBox class provides a modal dialog with a range of different messages, roughly arranged along two axes: severity and complexity. The message box has a different icon for each of the severity levels, but the icon must be specified explicitly. In our case we use the default QMessageBox::NoIcon value. In addition we use the default complexity, i.e. a message box showing the given text and an OK button.

At this stage in the program, the mouse could be completely uncalibrated, making the user unable to press the OK button. For that reason we use the static QTimer::singleShot() function to make the message box disappear after 10 seconds. The QTimer class provides repetitive and single-shot timers: The single shot function calls the given slot after the specified interval.

        Calibration cal;
        cal.exec();

Next, we create an instance of the Calibration class which is a dialog widget retrieving the required sample coordinates: The dialog sequentially presents five marks for the user to press, storing the device coordinates for the mouse press events.

        {
            QMessageBox message;
            message.setText("<p>The next screen will let you test the calibration "
                            "by drawing into a widget.</p><p>This program will "
                            "automaticly close after 20 seconds.<p>");
            QTimer::singleShot(10 * 1000, &message, SLOT(accept()));
            message.exec();
        }

        ScribbleWidget scribble;
        scribble.showMaximized();
        scribble.show();

        app.setActiveWindow(&scribble);
        QTimer::singleShot(20 * 1000, &app, SLOT(quit()));

        return app.exec();
    }

When the calibration dialog returns, we let the user test the new mouse settings by drawing onto a ScribbleWidget object. Since the mouse still can be uncalibrated, we continue to use the QMessageBox and QTimer classes to inform the user about the program's progress.

An improved calibration tool would let the user choose between accepting the new calibration, reverting to the old one, and restarting the calibration.

Calibration Class Definition

The Calibration class inherits from QDialog and is responsible for retrieving the device coordinates from the user.

    class Calibration : public QDialog
    {
    public:
        Calibration();
        ~Calibration();
        int exec();

    protected:
        void paintEvent(QPaintEvent*);
        void mouseReleaseEvent(QMouseEvent*);
        void accept();

    private:
        QWSPointerCalibrationData data;
        int pressCount;
    };

We reimplement QDialog's exec() and accept() slots, and QWidget's paintEvent() and mouseReleaseEvent() functions.

In addition, we declare a couple of private variables, data and pressCount, holding the Calibration object's number of mouse press events and current calibration data. The pressCount variable is a convenience variable, while the data is a QWSPointerCalibrationData object (storing the physical and logical coordinates) that is passed to the mouse handler. The QWSPointerCalibrationData class is simply a container for calibration data.

Calibration Class Implementation

In the constructor we first ensure that the Calibration dialog fills up the entire screen, has focus and will receive mouse events (the latter by making the dialog modal):

    Calibration::Calibration()
    {
        QRect desktop = QApplication::desktop()->geometry();
        desktop.moveTo(QPoint(0, 0));
        setGeometry(desktop);

        setFocusPolicy(Qt::StrongFocus);
        setFocus();
        setModal(true);

Then we initialize the QWSPointerCalibrationData::screenPoints array:

        int width = qt_screen->deviceWidth();
        int height = qt_screen->deviceHeight();

        int dx = width / 10;
        int dy = height / 10;

        QPoint *points = data.screenPoints;
        points[QWSPointerCalibrationData::TopLeft] = QPoint(dx, dy);
        points[QWSPointerCalibrationData::BottomLeft] = QPoint(dx, height - dy);
        points[QWSPointerCalibrationData::BottomRight] = QPoint(width - dx, height - dy);
        points[QWSPointerCalibrationData::TopRight] = QPoint(width - dx, dy);
        points[QWSPointerCalibrationData::Center] = QPoint(width / 2, height / 2);

In order to specify the calibration, the screenPoints array must contain the screen coordinates for the logical positions represented by the QWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft). Since non-linearity is expected to increase on the edge of the screen, all points are kept 10 percent within the screen. The qt_screen pointer is a reference to the screen device. There can only be one screen device per application.

        pressCount = 0;
    }

Finally, we initialize the variable which keeps track of the number of mouse press events we have received.

    Calibration::~Calibration()
    {
    }

The destructor is trivial.

    int Calibration::exec()
    {
        QWSServer::mouseHandler()->clearCalibration();
        grabMouse();
        activateWindow();
        int ret = QDialog::exec();
        releaseMouse();
        return ret;
    }

The reimplementation of the QDialog::exec() slot is called from the main program.

First we clear the current calibration making the following mouse event delivered in raw device coordinates. Then we call the QWidget::grabMouse() function to make sure no mouse events are lost, and the QWidget::activateWindow() function to make the top-level widget containing this dialog, the active window. When the call to the QDialog::exec() base function returns, we call QWidget::releaseMouse() to release the mouse grab before the function returns.

    void Calibration::paintEvent(QPaintEvent*)
    {
        QPainter p(this);
        p.fillRect(rect(), Qt::white);

        QPoint point = data.screenPoints[pressCount];
        p.fillRect(point.x() - 6, point.y() - 1, 13, 3, Qt::black);
        p.fillRect(point.x() - 1, point.y() - 6, 3, 13, Qt::black);
    }

The QWidget::paintEvent() function is reimplemented to receive the widget's paint events. A paint event is a request to repaint all or part of the widget. It can happen as a result of QWidget::repaint() or QWidget::update(), or because the widget was obscured and has now been uncovered, or for many other reasons. In our reimplementation of the function we simply draw a cross at the next point the user should press.

    void Calibration::mouseReleaseEvent(QMouseEvent *event)
    {
        QSize screenSize(qt_screen->width(), qt_screen->height());
        QPoint p = qt_screen->mapToDevice(event->pos(), screenSize);
        data.devPoints[pressCount] = p;

        if (++pressCount < 5)
            repaint();
        else
            accept();
    }

We then reimplement the QWidget::mouseReleaseEvent() function to receive the widget's move events, using the QMouseEvent object passed as parameter to find the coordinates the user pressed, and update the QWSPointerCalibrationData::devPoints array.

In order to complete the mapping between logical and physical coordinates, the devPoints array must contain the raw device coordinates for the logical positions represented by the QWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft)

We continue by drawing the next cross, or close the dialog by calling the accept() slot if we have collected all the required coordinate samples.

    void Calibration::accept()
    {
        Q_ASSERT(pressCount == 5);
        QWSServer::mouseHandler()->calibrate(&data);
        QDialog::accept();
    }

Our reimplementation of the QDialog::accept() slot simply activate the new calibration data using the QWSMouseHandler::calibrate() function. We also use the Q_ASSERT() macro to ensure that the number of required samples are present.

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 82
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  4. BlackBerry 10 : premières images du prochain OS de RIM qui devrait intégrer des widgets et des tuiles inspirées de Windows Phone 0
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. Adieu qmake, bienvenue qbs : Qt Building Suite, un outil déclaratif et extensible pour la compilation de projets Qt 17
  7. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 6
Page suivante

Le blog Digia au hasard

Logo

Créer des applications avec un style Metro avec Qt, exemples en QML et C++, un article de Digia Qt traduit par Thibaut Cuvelier

Le blog Digia est l'endroit privilégié pour la communication sur l'édition commerciale de Qt, où des réponses publiques sont apportées aux questions les plus posées au support. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.1
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web