Interfaces graphiques en C++ avec wxWidget/Dialogues

IHM en C++ avec wxWidget
Interfaces graphiques en C++ avec wxWidget
Interfaces graphiques en C++ avec wxWidget
Sommaire
Liens
Modifier ce modèle

Les boîtes de dialogue modifier

Nous étudierons ici un exemple qui calcule la distance entre 2 points du plan.


Notions abordées modifier

  • les boîtes de dialogue


Présentation de l'application modifier

L'objectif de cette application est d'avoir à l'écran les coordonnées de 2 points A et B dans des champs texte éditables. Deux boutons "Modifier A" et "Modifier B" permettent d'éditer les coordonnées des 2 boutons dans une boîte de dialogue modale.

Structuration en classe de l'application modifier

Notre application distance comportera 4 classes : la classe DistanceAppli qui représente notre application et qui hérite de wxApp, la classe DistanceWin qui héritera de wxframe et qui sera notre principale fenêtre, la classe Point qui permet de représenter un point et qui calcule la distance entre 2 points et la classe PointDialog qui permet d'éditer les coordonnées d'un point dans un boîte de dialogue.
Pour chacune de ces classes nous allons créer un fichier .h et un fichier .cpp. Nous aurons donc 8 fichiers au total :

  • DistanceAppli.h
  • DistanceAppli.cpp
  • DistanceWin.h
  • DistanceWin.cpp
  • Point.h
  • Point.cpp
  • PointDialog.h
  • PointDialog.cpp

La classe DistanceAppli modifier

Rien de nouveau par rapport aux leçons précédentes. La classe DistanceAppli ouvre une fenêtre de la classe DistanceWin. Le fichier DistanceAppli.h est le suivant :

#ifndef DISTANCEAPPLI_H
#define DISTANCEAPPLI_H

#include<wx/wx.h>
#include"DistanceWin.h"

class DistanceAppli : public wxApp
{
public:
    bool OnInit();

protected:
    DistanceWin * window;
};

DECLARE_APP(DistanceAppli)

#endif


Le fichier DistanceAppli.cpp est le suivant :

#include"DistanceAppli.h"

IMPLEMENT_APP(DistanceAppli)

bool DistanceAppli::OnInit()
{
  window=new DistanceWin();
  window->Show(TRUE);
  SetTopWindow(window);
  return true;
}


La classe DistanceWin modifier

La fenêtre de notre application est composée d'un wxPanel sur lequel on positionne du texte (classe wxStaticText), des champs texte (classe wxTextCtrl) qui seront rendus inéditables et des boutons (classe wxButton).
Cette classe comporte comme données membres deux points A et B (de la classe Point) et une méthode nommée ShowPoint(). Cette méthode va récupérer les coordonnées des 2 points A et B (grâce à des accesseurs getX() et getY()) ainsi que la distance entre les 2 points grâce à la méthode distance(..). Une fois ces informations récupérées, elles seront transformées en wxString et affichées dans les différents champs texte de la fenêtre.
Cette classe comportera également 2 autres méthodes editPointA et editPointB qui seront appelée lorsqu'on cliquera respectivement sur les boutons "MODIFIER A" et "MODIFIER B". Pour créer cette association, il faut écrire la macro DECLARE_EVENT_TABLE() dans le fichier DistanceWin.h à la fin de la déclaration de la classe DistanceWin .
Dans le fichier DistanceWin.cpp, il faut écrire :

BEGIN_EVENT_TABLE(DistanceWin,wxFrame)
EVT_BUTTON(BUTTONEDITA_ID,DistanceWin::editPointA)
EVT_BUTTON(BUTTONEDITB_ID,DistanceWin::editPointB)
END_EVENT_TABLE()


Les paramètres BUTTONEDITA_ID et BUTTONEDITB_ID sont des identifiants des 2 boutons issus d'un type énuméré. Lorsqu'on appelle les méthodes editPointA et editPointB, il faut créer une nouvelle boîte de dialogue de la classe PointDialog en passant au constructeur de cette classe le nom et l'instance du point à éditer. Il faut ouvrir cette boîte de dialog en appelant la méthode ShowModal(). Lorsque la boîte de dialogue se referme, il faut mettre à jour les coordonnées des points et la distance en appelant la méthode ShwPoint().
Le fichier DistanceWin.h est le suivant :

#ifndef DISTANCEWIN_H
#define DISTANCEWIN_H

#include<wx/wx.h>
#include"Point.h"

enum
{
  BUTTONEDITA_ID ,BUTTONEDITB_ID
};

class DistanceWin : public wxFrame
{
public:
    DistanceWin();

protected:
    wxPanel * panel;

    wxStaticText *textXA,*textXB,*textYA,*textYB,*textDistance;
    wxTextCtrl *editXA,*editXB,*editYA,*editYB,*editDistance;
    wxButton *editA,*editB;

    Point A,B;

    void ShowPoint();
    void editPointA(wxCommandEvent &event);
    void editPointB(wxCommandEvent &event);
    DECLARE_EVENT_TABLE()
};

#endif


Le fichier DistanceWin.cpp est le suivant :

#include"DistanceWin.h"
#include"PointDialog.h"

DistanceWin::DistanceWin()
    : wxFrame(NULL,-1,"Distance",wxPoint(10,10),wxSize(400,300))
{
  panel= new wxPanel(this);

  textXA=new wxStaticText(panel,-1,"Abscisse de A : ",wxPoint(10,20),wxSize(100,20));
  textYA=new wxStaticText(panel,-1,"Ordonnée de A : ",wxPoint(10,50),wxSize(100,20));
  textXB=new wxStaticText(panel,-1,"Abscisse de B : ",wxPoint(10,90),wxSize(100,20));
  textYB=new wxStaticText(panel,-1,"Ordonnée de B : ",wxPoint(10,120),wxSize(100,20));
  textDistance=new wxStaticText(panel,-1,"La distance AB : ",wxPoint(10,180),wxSize(200,20));

  editXA=new wxTextCtrl(panel,-1,"",wxPoint(120,20),wxSize(100,20));
  editXA->SetEditable(false);
  editXA->SetBackgroundColour(wxColour(200,200,200));
  editYA=new wxTextCtrl(panel,-1,"",wxPoint(120,50),wxSize(100,20));
  editYA->SetEditable(false);
  editYA->SetBackgroundColour(wxColour(200,200,200));
  editXB=new wxTextCtrl(panel,-1,"",wxPoint(120,90),wxSize(100,20));
  editXB->SetEditable(false);
  editXB->SetBackgroundColour(wxColour(200,200,200));
  editYB=new wxTextCtrl(panel,-1,"",wxPoint(120,120),wxSize(100,20));
  editYB->SetEditable(false);
  editYB->SetBackgroundColour(wxColour(200,200,200));
  editDistance=new wxTextCtrl(panel,-1,"",wxPoint(120,180),wxSize(100,20));
  editDistance->SetEditable(false);
  editDistance->SetBackgroundColour(wxColour(200,200,200));

  editA=new wxButton(panel,BUTTONEDITA_ID,"MODIFIER A",wxPoint(240,35));
  editB=new wxButton(panel,BUTTONEDITB_ID,"MODIFIER B",wxPoint(240,105));

  ShowPoint();
}

void DistanceWin::editPointA(wxCommandEvent &event)
{
  PointDialog *dialog=new PointDialog(this,"Modification du Point A",A);
  dialog->ShowModal();
  ShowPoint();
}

void DistanceWin::editPointB(wxCommandEvent &event)
{
  PointDialog *dialog=new PointDialog(this,"Modification du Point B",B);
  dialog->ShowModal();
  ShowPoint();
}

void DistanceWin::ShowPoint()
{
  wxString s;
  s.sprintf("%lf",A.getX());
  editXA->SetValue(s);
  s.sprintf("%lf",A.getY());
  editYA->SetValue(s);
  s.sprintf("%lf",B.getX());
  editXB->SetValue(s);
  s.sprintf("%lf",B.getY());
  editYB->SetValue(s);
  s.sprintf("%lf",A.distance(B));
  editDistance->SetValue(s);
}

BEGIN_EVENT_TABLE(DistanceWin,wxFrame)
    EVT_BUTTON(BUTTONEDITA_ID,DistanceWin::editPointA)
    EVT_BUTTON(BUTTONEDITB_ID,DistanceWin::editPointB)
END_EVENT_TABLE()


La classe Point modifier

La classe Point comportera 2 données membres privées x et y qui représentent les coordonnées du point, un constructeur qui initialise à 0 les coordonnées des points, 2 accesseurs getX() et getY() et 1 mutateur setXY(int x, int y). Elle possède également une méthode distance pour calculer la distance entre 2 points.
Le fichier Point.h est le suivant :

#ifndef POINT_H
#define POINT_H

class Point
{
public:
    Point();
    double getX();
    double getY();
    void setXY(double x, double y);

    double distance(const Point &P);

private:
    double x,y;

};

#endif


Le fichier Point.cpp est le suivant :

#include"Point.h"
#include<cmath>

Point::Point():x(0),y(0)
{
}

double Point::getX() { return x; }

double Point::getY() { return y; }

void Point::setXY(double x, double y)
{
  this->x=x;
  this->y=y;
}

double Point::distance(const Point &P)
{
  double dx,dy;
  dx=x-P.x;
  dy=y-P.y;
  return sqrt(dx*dx+dy*dy);
}


La classe PointDialog modifier

La classe PointDialog est une boîte de dialogue modale qui permet d'éditer les coordonnées d'un point. Elle hérite à ce titre de la classe prédéfinie wxDialog.
La boîte est modale, c'est-à-dire que lorsqu'on l'ouvre, l'application est bloquée jusqu'à ce qu'on la ferme en cliquant sur le bouton OK ou Annuler.
Le constructeur de la boîte de dialogue aura 3 paramètres :

  • le composant parent de cette boîte de dialogue : ce sera un pointeur vers la fenêtre de notre application.
  • une chaîne de caractères wxString qui indique le titre de notre fenêtre. En pratique ce sera "Modification du point A" ou "Modification du point B".
  • une référence vers le point à modifier. L'initialisation de cette référence se fera via la liste d'initialisation.

Le constructeur de PointDialog appelle le constructeur de wxDialog. Ce dernier a besoin des informations suivantes :

  • le wxWidget parent de la boîte de dialogue.
  • un identifiant que nous n'utiliserons pas (valeur -1).
  • le titre de la boîte de dialogue
  • la position de la boîte de dialogue de la classe wxPoint().
  • la taille de la boîte de dialogue de la classe wxSize().

Ce constructeur va dans un premier temps créer les différents composants graphiques : des wxStaticText, des champs texte éditables de la classe wxTextCtrl et les boutons OK et Annuler qui auront des identifiants prédéfinis : respectivement wxID_OK et wxID_CANCEL.

Une fois ces composants graphiques positionnés, on affichera les coordonnées du point passé par référence en appelant la méthode ShowPoint(). Cette méthode récupérera les coordonnées du point en appelant les accesseurs, transformera ces données en chaînes de caractères et affichera ces chaînes dans les champs texte correspondant.

Lorsqu'on cliquera sur le bouton Annuler, ce bouton ayant l'identifiant wxID_CANCEL, la boîte de dialogue sera tout simplement fermée.

Lorsqu'on cliquera sur le bouton OK, ce bouton ayant l'identifiant wxID_OK, alors on appellera automatiquement la méthode virtuelle bool Validate(). Si cette méthode renvoie true, alors la boîte de dialogue sera fermée, sinon elle restera ouverte. Nous redéfinissons la méthode Validate dans notre classe PointDialog : cette méthode récupère les chaînes saisies pour l'abscisse et l'ordonnée du point. Elle essaye ensuite de transformer ces chaînes en double en appelant la méthode ToDouble sur la classe wxString. Si les 2 coordonnées sont correctes, alors on modifiera les coordonnées du point (passé par référence) en appelant le mutateur setXY(...). Dans le cas contraire, un message d'erreur sera affiché en appelant la fonction wxMessageBox("Les données ne sont pas valides","ERREUR");.

Le fichier PointDialog.h est le suivant :

#ifndef POINTDIALOG_H
#define POINTDIALOG_H

#include<wx/wx.h>
#include"Point.h"

class PointDialog : public wxDialog
{
public:
    PointDialog(wxWindow * parent,wxString titre, Point &P);

private:
    Point &P;

    wxStaticText *textX,*textY;
    wxTextCtrl *editX,*editY;
    wxButton *OK,*Cancel;

    void ShowPoint();
    bool Validate();
};

#endif


Le fichier PointDialog.cpp est le suivant :

#include"PointDialog.h"

PointDialog::PointDialog(wxWindow * parent,wxString titre, Point &P):
    wxDialog(parent,-1,titre,wxPoint(500,100),wxSize(400,200)),P(P)
{
  textX=new wxStaticText(this,-1,"Abscisse du point : ",wxPoint(10,20),wxSize(100,20));
  textY=new wxStaticText(this,-1,"Ordonnée du point : ",wxPoint(10,50),wxSize(100,20));
  editX=new wxTextCtrl(this,-1,"",wxPoint(120,20),wxSize(100,20));
  editY=new wxTextCtrl(this,-1,"",wxPoint(120,50),wxSize(100,20));

  OK=new wxButton(this,wxID_OK,"OK",wxPoint(260,20));
  Cancel=new wxButton(this,wxID_CANCEL,"Annuler",wxPoint(260,50));

  ShowPoint();
}

void PointDialog::ShowPoint()
{
  wxString s;
  s.sprintf("%lf",P.getX());
  editX->SetValue(s);
  s.sprintf("%lf",P.getY());
  editY->SetValue(s);
}

bool PointDialog::Validate()
{
  double x,y;
  bool okx,oky,ok;
  wxString s;

  s=editX->GetValue();
  okx=s.ToDouble(&x);
  s=editY->GetValue();
  oky=s.ToDouble(&y);
  ok=okx && oky;
  if(ok) P.setXY(x,y);
  else wxMessageBox("Les données ne sont pas valides","ERREUR");
  return ok;
}