Gestion d'une interface graphique avec Qt

Cet exercice détaille pas à pas la prise en main de Qt et nous prépare à la modification de l'interface graphique de DrawQt afin d'y ajouter les boutons qui sélectionnent les différentes formes graphiques.

On s'attachera à appliquer systématiquement les deux outils que l'on connaît désormais: SVN et Doxygen.

Les étapes 1 : Création d'une première application Qt
2 : Premier pas SIGNAL / SLOT
3 : Ajout d'un menu
4 : Ajout d'un nouveau SLOT

Étape 1 : Création d'une première application Qt

Cette première étape, variante de bonjour, permet de créer notre première application Qt et de se familiariser avec cet outil.

On commence par définir son environnement Svn :

$> cd ~/Project
$> mkdir TpQt
$> svn add TpQt
$> svn ci -m "Creating the TpQt directory"
Dans cet exercice nous allons commencer de structurer le répertoire source contenant le code dans deux répertoires: include, pour les définitions des classes (fichiers *.h), et src pour les implantations des classes (fichiers *.cxx):

$> cd ~/Project/TpQt
$> mkdir source
$> cd ~/Project/TpQt/source
$> mkdir include src
Puis, pour créer la classe de base, on édite ensuite le fichier d'entête de la classe include/MyWindow.h :
#ifndef MYWINDOW_H
#define MYWINDOW_H

#include <QtGui/QMainWindow>
#include <QtGui/QPushButton>

/// \file   MyWindow.h
/// \author IPN teaching <ivana@ipno.in2p3.fr>
/// \date   November 2008
///
/// \brief  First class MyWindow based on Qt

class MyWindow : public QMainWindow
{
  // Macro Q_OBJECT necessary to specify the use of Qt internal mechanism 
  // for communication between classes. 
  Q_OBJECT
  
  public:
    /// \brief The main constructor
    MyWindow( QMainWindow* parent = 0, Qt::WFlags fl = Qt::Window );

    /// \brief Destructor of the class
    virtual ~MyWindow();
  
  private:
    QPushButton* m_hello; ///< our push button
};

#endif // MYWINDOW_H
Puis, on édite le fichier d'implémentation de la classe src/MyWindow.cxx :
/// \file   MyWindow.cxx
/// \author IPN teaching <ivana@ipno.in2p3.fr>
/// \date   November 2008
/// 
/// \brief  First class MyWindow based on Qt

#include "MyWindow.h"

/// Method for creating the MyWindow class <br />
/// Our class, which will be be a graphical window display, 
/// should inherit from the Qt  QMainWindow class 
/// \param parent : Parent widget, parent of the class. In our case, 
/// this is the main window, so the parent will be "NULL"
/// \param flags :  The creation flags of the window. Can be used 
/// to create a non-rediomensionnable window, without an exit button ... etc. ...
MyWindow::MyWindow( QMainWindow* parent, Qt::WFlags fl )
   : QMainWindow( parent, fl )
{
   // Create our  push button
   m_hello = new QPushButton( "Hello world!" );  
                 // put the text that you want to see ... 

   // Display our button in a central position
   setCentralWidget( m_hello );
}

/// Destroy object MyWindow and all objects contained inside.
/// In particular, the button previously created.
MyWindow::~MyWindow()
{
   delete m_hello;
}
La classe MyWindow hérite de la Qt classe QMainWindow, et la documentation peut être consultée sur le Qt4 site . Vous devriez consulter ce site à chaque fois quand nous rencontrons un nouveau classe QT4.

Puis ajouter la fonction main dans le fichier QtTest.cxx:

/// \file   QtTest.cxx
/// \author IPN teaching <ivana@ipno.in2p3.fr>
/// \date   November 2008

/// \brief  First HelloWorld in Qt

#include <QApplication>
#include <QPushButton>

#include <MyWindow.h>

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   MyWindow* myWindow = new MyWindow();
   myWindow->show();
   return app.exec();
}
Pour construire nôtre application, nous allons utiliser l'outil qmake , disponible avec Qt, pour configurer le project et générer automatiquement Makefile.
$> cd ~/Project/TpQt
$> qmake -project
$> qmake -spec macx-g++
Il faut encore récuperer et adapter le fichier Doxyfile pour le nouveau projet. Pour que DDoxygenD trouve les classes dans le répertoire structuré, il faut aussi modifier le paramétre RECURSIVE:
RECURSIVE              = YES
Reste à construire et tester l'application :
$> make
$> open TpQt.app
$> doxygen
On peut alors sauvegarder la version dite de départ dans SVN:
$> svn add source Doxyfile
$> svn ci -m "First version" . 
On peut ensuite commencer de modifier les fichiers source qui seront versionnés.
Les étapes 1 : Création d'une première application Qt
2 : Premier pas SIGNAL / SLOT
3 : Ajout d'un menu
4 : Ajout d'un nouveau SLOT

Étape 2 : Ajout d'un SIGNAL / SLOT sur le boutton

Comme vous l'avez remarqué, aucune action n'est associée au bouton de notre application. Afin d'y remédier, on va utiliser le mécanisme de SIGNAL / SLOT de Qt.
L'objet éméteur sera le bouton m_hello.
Le signal envoyé sera l'action du clic souris.
L'objet receveur sera l´objet myWindow (de type QMainWindow).
Pour finir, le slot sera la méthode close() (de la classe QMainWindow).

Pour cela, il suffit simplement d'ajouter la ligne suivante, juste après la création du bouton, dans MyWindow.cxx:

   // Connect the clicked() signal of the graphical button to the QMainWindow  
   // method close()
   connect( m_hello, SIGNAL(clicked()), this, SLOT(close()) );
Reste à construire et tester l'application puis la sauver SVN:
$> make
$> doxygen
$> open TpQt.app
$> svn ci -m "Activation of a graphics button" .
Les étapes 1 : Création d'une première application Qt
2 : Premier pas SIGNAL / SLOT
3 : Ajout d'un menu
4 : Ajout d'un nouveau SLOT

Étape 3 : ajout d'un menu

On va désormais ajouter un menu à notre fenêtre.

Ajouter les includes suivants dans le fichier MyWindow.cxx:

#include <QMenu>
#include <QMenuBar>

Puis ajouter le code suivant dans le constructeur de la classe MyWindow :

MyWindow::MyWindow( QMainWindow* parent, Qt::WFlags fl )
   : QMainWindow( parent, fl )
{
   //...

   // Display button in a central position
   setCentralWidget(m_hello);

   // Creation of menuBar
   QMenuBar* menuBar = new QMenuBar(this);

   // Creating a menu "File"
   QMenu* menuFile = new QMenu("File");

   // And adding the menu "File" in the menu bar
   menuBar->addMenu(menuFile);

   // Now we add our items 
   // Add an item "Open" 
   menuFile->addAction("Open");

   // Add a separator
   menuFile->addSeparator();

   // Add an item "Bye" connected to the slot  "close" of the mainWindow 
   menuFile->addAction("Bye", this, SLOT(close()) );

   // Then set the menu bar to the main window
   setMenuBar(menuBar);
}
On reconstruit, on teste et on sauvegarde dans SVN.
Les étapes 1 : Création d'une première application Qt
2 : Premier pas SIGNAL / SLOT
3 : Ajout d'un menu
4 : Ajout d'un nouveau SLOT

Étape 4: Ajout d'un nouveau SLOT

On désire maintenant ajouter notre propre action lors du clic sur un menu.

Pour cela, nous allons commencer par ajouter une action "Change" à notre menu "File", que l'on va connecter à la fonction change() définie par la suite. À la suite de la création de l'action "Open" ajouter les lignes suivantes :

   // Add a new item "Change" that connects to the function change()
   menuFile->addAction("Change", this, SLOT(change()) );
Puis, on ajoute la fonction change() qui sera exécutée lors de l'appel du menu "Change". Cette fonction étant appellée par un événement (clic sur un menu), c'est donc un nouveau SLOT que l'on va définir.
Dans le fichier MyWindow.h, ajouter dans l'entête de la classe les lignes suivantes:
  public slots :
    void change();
Puis, le corps de la fonction, à ajouter dans le fichier myWindow.cxx:
/// This method changes the text button m_hello. 
/// The documentation for the QPushButton methods is available at: 
/// <a href="http://doc.trolltech.com/4.0/qpushbutton.html">QPushButton</a><br />
/// The QPushButton is a special type of button. Possible buttons are 
/// PushButton, CheckButton, RadioButton ... etc. ... They all inherit 
/// the properties of an abstract button type called QAbstractButton. 
/// The documentation on QAbstractButton methods is available at: 
/// <a href="http://doc.trolltech.com/4.0/qabstractbutton.html">QAbstractButton</a><br />

void MyWindow::change()
{
   m_hello->setText("..."); 
     // Complete the line above according to the documentation
}
On reconstruit, on teste et on sauvegarde dans SVN.
Valid XHTML 1.0! Valid CSS!
Contact: ivana@ipno.in2p3.fr
Last modified: 27/10/2011