Damier à base de boutons

Il serait aisé de placer les boutons manuellement quand il y en a peu, mais que faire si le nombre de bouton est important?

Création du damier

La première opération consiste à créer la fenêtre du jeu.

On pourra reprendre les manipulations détaillées au chapitre Indispensables/Fichiers d'un projet.

Les boutons devant être judicieusement placés sur la zone de jeu, il est opportun de faire appel à un GridLayout.

  • Placer le GridLayout dans la fenêtre de l'application

  • L'objet s'appelle gridLayout et dispose de 6 pixels de marge droite et basse
  • Sauver QT Designer

Ajouter les boutons

Les boutons seront ajoutés dans le code de la fenêtre (ici mainwin).

mainwin.cpp

#include "mainwin.h"

#include "ui_mainwin.h"

#include <QtWidgets>


mainwin::mainwin(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::mainwin)

{

    ui->setupUi(this);

    QVector<QPushButton*> mesBoutons(100);

    for(int i = 0; i < 100; i++)

        {

        mesBoutons[i] = new QPushButton("", this);

        mesBoutons[i]->setMinimumWidth(40);

        mesBoutons[i]->setMinimumHeight(40);

        }

    for(int i = 0; i < 100; i++)

        {

         ui->gridLayout->addWidget(mesBoutons.at(i),i/10,i%10);

        }

}


mainwin::~mainwin()

{

    delete ui;

}

On créé un vecteur de 100 boutons, de taille minimum 40x40 pixels.

Ces boutons sont ensuite placés dans le layout (gridLayout) de la fenêtre (ui)

AddWidget prend comme argument (dans le cas où il est associé à un GridLayout) le widget à placer, la ligne de placement, puis la colonne.

Ajouter les slots

Nous souhaitons qu'un clic sur un bouton ouvre une fenêtre informant de la touche appuyée.


A ce stade de notre programme, un clic sur le bouton ne produit rien.

Il faut associer des connexions à chaque bouton.

Voir à ce sujet la gestion des slots.

Il est impossible de lier le slot au bouton par un paramètre.

On ne peut donc pas faire ça :

QObject::connect(ActionBoutons[i], SIGNAL(clicked()), this, SLOT(boutonclic(i)));


Pour résoudre ce problème, il faut rajouter un SignalMapper.

Le SignalMapper fournit un moyen d'établir une relation entre un ensemble de signaux sans paramètres et un signal ou un slot ayant un seul paramètre.


Il faut donc ajouter le SignalMapper dans le code de mainwin.cpp :

mainwin::mainwin(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::mainwin)

{

    ui->setupUi(this);

    QVector<QPushButton*> mesBoutons(100);

    QSignalMapper *signalMapper = new QSignalMapper(this);

    QObject::connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(boutonclic(int)));


    for(int i = 0; i < 100; i++)

        {

        mesBoutons[i] = new QPushButton("", this);

        mesBoutons[i]->setMinimumWidth(40);

        mesBoutons[i]->setMinimumHeight(40);

        signalMapper->setMapping(mesBoutons[i],i);

        QObject::connect(mesBoutons[i], SIGNAL(clicked()), signalMapper, SLOT(map() ));

        }

    for(int i = 0; i < 100; i++)

        {

         ui->gridLayout->addWidget(mesBoutons.at(i),i/10,i%10);

         }


}


QSignalMapper *signalMapper = new QSignalMapper(this) : Créé l'instance de QSignalMapper

QObject::connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(boutonclic(int))) : SignalMapper permet la connexion vers un SLOT possédant un paramètre. Ce sera le numéro de notre bouton. Lorsque signalMapper génère un événement mapped il le redirige vers la procédure boutonclic.

signalMapper->setMapping(mesBoutons[i],i) : A chaque itération, on rajoute un nouvel élément à signalMapper constitué du nouveau bouton et de son numéro

QObject::connect(mesBoutons[i], SIGNAL(clicked()), signalMapper, SLOT(map() )) : connexion entre les boutons et signalMapper. Lorsqu'un bouton est cliqué signalMapper génère une action mapped.


Il reste ensuite à créer la procédure qui gère l'action :

........

void mainwin::boutonclic(int num)

{

    QString texte;

    texte="Touche "+QString::number(num)+" appuyée";

  QMessageBox::information(this,"Information",texte);

}


mainwin::~mainwin()

{

    delete ui;

}


 et à rajouter les déclarations dans l'entête :

#ifndef MAINWIN_H

#define MAINWIN_H


#include <QMainWindow>

#include <QtWidgets/QMessageBox>


namespace Ui {

class mainwin;

}


class mainwin : public QMainWindow

{

    Q_OBJECT


public:

    explicit mainwin(QWidget *parent = 0);

    ~mainwin();

public slots:

public slots:

    void boutonclic(int num);

private:

    Ui::mainwin *ui;

};


#endif // MAINWIN_H

Le code complet :

mainwin.h

#ifndef MAINWIN_H

#define MAINWIN_H

#include <QMainWindow>

#include <QtWidgets/QMessageBox>

#include <QVector>

#include <QSignalMapper>

#include <QPushButton>

namespace Ui {

class mainwin;

}


class mainwin : public QMainWindow

{

    Q_OBJECT


public:

    explicit mainwin(QWidget *parent = 0);

    ~mainwin();

public slots:

public slots:

    void boutonclic(int num);

private:

    Ui::mainwin *ui;

    QVector<QPushButton*> mesBoutons;

    QSignalMapper *signalMapper;

};


#endif // MAINWIN_H

main.cpp

#include <QApplication>

#include "mainwin.h"


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

{

   QApplication app(argc, argv);


   mainwin fenetre; //on créé une instance de l'objet mainwin

   fenetre.show(); //et on l'affiche


   return app.exec();

}

mainwin.cpp

#include "mainwin.h"

#include "ui_mainwin.h"

#include <QtWidgets>

//*********************************************************************************************************

mainwin::mainwin(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::mainwin)

{

    ui->setupUi(this);

   signalMapper = new QSignalMapper(this);

    QObject::connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(boutonclic(int)));


    for(int i = 0; i < 100; i++)

        {

         mesBoutons.append(new QPushButton("", this));

        mesBoutons[i]->setMinimumWidth(40);

        mesBoutons[i]->setMinimumHeight(40);

        signalMapper->setMapping(mesBoutons[i],i);

        QObject::connect(mesBoutons[i], SIGNAL(clicked()), signalMapper, SLOT(map() ));

        }

    for(int i = 0; i < 100; i++)

        {

         ui->gridLayout->addWidget(mesBoutons.at(i),i/10,i%10);

         }

}

//********************************************************************************************************

void mainwin::boutonclic(int num)

{

    QString texte;

    texte="Touche "+QString::number(num)+" appuyée";

  QMessageBox::information(this,"Information",texte);

}

//*********************************************************************************************************

mainwin::~mainwin()

{

    delete ui;

}


Le formulaire mainwin.ui