Catégorie : Programmation     Tags : ,      

    Retrouvez cet article dans : Linux Magazine 83

    Cet article présente quelques contrôles présents dans la plupart des applications. Il permet ainsi d’étendre les notions des articles précédents. Le positionnement de ces contrôles est limité pour introduire plus tard des notions nouvelles sur les méthodes de placement.

    1. Introduction

    Cette publication se veut (comme les précédentes) être indépendante et compréhensible pour les personnes n’ayant pas lu les deux premiers articles (même si ceux-ci abordent plus en détail certains aspects de la bibliothèque).
    Suite à quelques interrogations de lecteurs concernant les articles précédents, je précise qu’il est possible d’utiliser les programmes sur les différents OS existants, même si ici il s’agit bien d’une revue dédiée au système GNU/Linux. Cependant, en version de base, les différentes distributions sous l’environnement graphique KDE permettent d’utiliser le logiciel de conception d’interfaces Qt Designer et celui-ci comme son nom l’indique est lié à la bibliothèque Qt.
    Pour la réalisation d’interfaces avec wxWidgets, il y a (cf. premier article) wxGlade ou wxFormBuilder par exemple (ou Boa Constructor en Python). En revanche, il faut faire attention à la licence de la bibliothèque choisie, dans le cas de wxWidgets il s’agit de la LGPL modifiée permettant une liaison statique avec les programmes utilisés commercialement.
    La compilation des programmes se fait avec la ligne de commande suivante : g++ mon_prog.cpp -o mon_prog `wx-config --libs - -cppflags`. Le ` est obtenu par la combinaison des touches [ALT GR]+[7]. Cette petite introduction permettra de répondre à quelques questions posées concernant wxWidgets. Mais maintenant passons à une partie plus intéressante : la découverte de quelques contrôles. Il ne s’agit pas de présenter les fonctionnalités des contrôles, mais simplement de donner un exemple de création, d’utilisation ou de modification du widget concerné.

    2. Présentation de quelques widgets

    2.1 Les boutons : wxButton

    /img-articles/lm/83/cc-art-wxwidget/fig-1.jpg

    Fig. 1 : 2 boutons dans une fenêtre

    Il existe plusieurs types de boutons : simple, à image, double état. Les événements générés sont identiques à ceux émis par les menus puisqu’il s’agit du type wxCommandEvent.
    Cela permet de récupérer dans une fenêtre parent les événements wxEVT_COMMAND_BUTTON_CLICKED (sauf les boutons de type wxToggleButton qui sont similaires à des cases à cocher au niveau fonctionnalités, mais avec le graphisme d’un bouton).
    Afin de récupérer les événements, il suffit d’utiliser la macro EVT_BUTTON(id, func) avec id le numéro associé au bouton (ou wxID_ANY pour les événements de tous les boutons) et func la méthode de récupération de la classe du bouton. On a alors la fenêtre figure 1 :

    class MyCountButton : public wxButton
    {
     public:
      MyCountButton(wxWindow* parent, wxWindowID id, wxString label,wxPoint pos,
                    wxSize size, long style);
      void OnClick(wxCommandEvent& event);
      DECLARE_EVENT_TABLE() // déclaration d’une table d’événements
      private:
        int nb; // pour compter les clics
    };
    
    BEGIN_EVENT_TABLE(MyCountButton,wxButton) // début table d’événements
     EVT_BUTTON(wxID_ANY,MyCountButton::OnClick) // gestion des clics
    END_EVENT_TABLE() // fin de la table des événements
    
    MyCountButton::MyCountButton(wxWindow* parent, wxWindowID id, wxString label = wxEmptyString,wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, long style = 0) : wxButton(parent,id,label,pos,size,style),nb(0)
    {
    }
    
    void MyCountButton::OnClick(wxCommandEvent& event)
    {
     nb++;
     SetLabel(wxString::Format(“%d”,nb));
     event.Skip(); // on transmet l’événement à la classe de base
    }
    
    bool MyApp::OnInit() // si l’application est MyApp
    {
     wxFrame *frame = new wxFrame(NULL,wxID_ANY,wxEmptyString);
     // Dans le code on a alors une déclaration du type
     MyCountButton* button=new MyCountButton(frame,wxID_ANY,wxT("Bouton"),wxPoint(5,5),
                                         wxSize(50,30),wxBU_LEFT|wxBU_TOP);
      button=new MyCountButton(frame,wxID_ANY,wxT("Bouton"),wxPoint(40,40),wxSize(80,40));
      frame->Show(true); // on montre la fenêtre
      SetTopWindow(frame);
      return true;
    }
    
    

    Déclaration d’une nouvelle classe MyCountButton

    Ici on a créé un nouveau type de bouton : un " bouton comptant " ayant comme label le nombre de clics de souris. Mais il est peu probable que la gestion et le traitement d’un clic se fassent au niveau de la classe du bouton.
    Dans cet exemple, c’est le cas, car il s’agit simplement de montrer une extension des fonctionnalités d’un bouton. En règle générale, le traitement s’effectue au niveau du parent du bouton ou plus précisément d’un objet de type fenêtre ou panneau (wxFrame ou wxPanel).
    Cela explique le fait que l’événement soit du type wxCommandEvent pour permettre le traitement au niveau du parent. Cela se produit si le premier gestionnaire d’événements (donc ici le bouton lui-même) ne récupère pas l’événement ou si on ne le laisse pas se propager en utilisant la méthode Skip().
    Pour traiter les événements, il suffit d’ajouter simplement une table similaire à celle présentée dans la fenêtre contenant le bouton. Lors de la lecture du code, on pourrait penser qu’il y a une erreur car le pointeur button est assigné deux fois sans libération de mémoire.
    En regardant bien on constate que le bouton est déclaré avec comme parent la fenêtre référencée par le pointeur frame. Cela a pour effet que toute fermeture de fenêtre entraînera la destruction des éléments contenus dans celle-ci.
    De plus, si vous regardez bien le bouton, vous pouvez voir un cadre en pointillé qui indique qu’un simple appui sur la touche [entrée] permet de presser le bouton.
    Vous pouvez aussi récupérer les événements du clavier (macro EVT_KEY_DOWN) pour changer ce fonctionnement (cf. méthode de récupération des touches de l’article précédent de mars 2006).

    2.2 La case à cocher : wxCheckBox

    /img-articles/lm/83/cc-art-wxwidget/fig-2.jpg

    Très utilisée pour sélectionner des options, il s’agit d’un contrôle simple offrant 2 positions en fonctionnement classique et une troisième en fonctionnement étendu.
    Comme pour les boutons, un événement de type wxCommandEvent est généré lors d’un clic sur le contrôle.
    Cela permet donc de mettre le traitement (s’il existe) dans la fenêtre parent. Le code est alors le suivant :

     

    wxCheckBox* box=new wxCheckBox(frame,wxID_ANY,wxT("Une case à cocher”),wxPoint(40,100));

    Déclaration d’une case à cocher

    La réception de l’événement lié au changement d’état par l’utilisateur (utilisation de la macro EVT_CHECKBOX) est justifiée si on doit changer immédiatement un élément visuel (une fenêtre ou tout autre élément).
    Dans le cas contraire, il est préférable de lire la case en utilisant la méthode GetValue() qui renvoie true ou false suivant l’état.

    2.3 La liste de valeurs : wxComboBox

    /img-articles/lm/83/cc-art-wxwidget/fig-3.jpg

    Figure 2 : ComboBox dans une fenêtre

    Il s’agit à la fois d’une zone d’édition et d’une zone de sélection. Ce widget permet de sélectionner une valeur. Il fait partie du groupe des contrôles avec éléments.
    Il est à utiliser pour éviter de surcharger une fenêtre et d’avoir une liste déroulante uniquement en cas de sélection. Les événements associés sont au nombre de 3 et sont de type wxCommandEvent :

    • la sélection d’une valeur de la liste : utilisation de la macro EVT_COMBOBOX(id, func) avec id, le code identificateur de la ComboBox, et func, la méthode de traitement du changement ;
    • la rentrée de texte : utilisation de la macro EVT_TEXT(id, func) ;
    • la frappe de la touche [entrée] : utilisation de la macro EVT_TEXT_ENTER(id, func).

    Le code de la création est alors le suivant :

     

    wxString tab[]={wxT("Premier"),wxT("Deuxieme"),wxT("Troisieme")};
    wxComboBox* combobox=new wxComboBox(frame,wxID_ANY,wxT("Un texte"),wxPoint(5,5),wxDefaultSize,3,tab);

    Déclaration d’une liste de valeurs : ComboBox

    Il existe aussi une autre possibilité sans édition identique à la ComboBox : wxChoice.

    2.4 La barre de progression : wxGauge

    /img-articles/lm/83/cc-art-wxwidget/fig-4.jpg

    Un composant utile pour signaler un calcul en cours ou pour faire office d’indicateur de niveau. La jauge est simplement un widget visuel. Donc, il n’y a aucun événement dans la version de base.
    Nous allons donc ici créer une nouvelle jauge permettant sur un simple clic de changer la valeur de celle-ci (à condition que la souris soit dans la jauge bien sûr). Pour la version de base on a :

    // Jauge de valeur minimale 0 et maximale 1000
    wxGauge *gauge=new wxGauge(frame,wxID_ANY,1000,wxDefaultPosition,wxSize(500,40));
    gauge->SetValue(300); // on fixe la valeur à 300
    gauge->SetBackgroundColour(*wxCYAN); // on change la couleur

    Déclaration d’une jauge (version de base)

    Pour la version avec possibilité de changer la valeur d’un simple clic, on a alors le code suivant :

     class MyClickGauge : public wxGauge
    {
     public:
      MyClickGauge(wxWindow* parent, wxWindowID id, int range, wxPoint  pos, wxSize size);
      void OnMouseClick(wxMouseEvent& event); // gestion du click
      DECLARE_EVENT_TABLE() // déclaration de la table d’événements
    };
    
    BEGIN_EVENT_TABLE(MyClickGauge,wxGauge) // déclaration de la table d’événements
     EVT_LEFT_DOWN(MyClickGauge::OnMouseClick) // événement click gauche de la souris
    END_EVENT_TABLE() // fin de la table
    
    void MyClickGauge::OnMouseClick(wxMouseEvent& event)
    {
     SetValue((GetRange()*event.GetX())/GetSize().GetWidth()); // on change la valeur
    }
    
    MyClickGauge::MyClickGauge(wxWindow* parent, wxWindowID id, int range, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize) : wxGauge(parent,id,range,pos,size)
    {
    }

     

    Déclaration d’une jauge avec gestion du clic souris

    De plus, l’utilisation est la même que celle de la jauge de base.

    2.5 Le texte : wxTextCtrl

    /img-articles/lm/83/cc-art-wxwidget/fig-5.jpg

    Fig. 3 : TextCtrl dans une fenêtre

    Composant permettant l’édition d’une ligne ou de plusieurs lignes de texte suivant la configuration du contrôle. C’est un composant assez complexe et riche dans ses fonctionnalités. Il sera présenté plus en détail dans des articles ultérieurs. Ici une simple déclaration et utilisation sont données.
    Comme on peut le voir sur la figure 3, la possibilité est laissée à l’utilisateur de mettre de la couleur, de changer la police ou la taille et des ascenseurs sont créés si la taille du texte est trop importante. Le code pour obtenir cette figure est le suivant :

     

    wxTextCtrl *text=new wxTextCtrl(frame,wxID_ANY,wxT("Un texte\n"),wxPoint(5,5),
              			   wxSize(200,80),wxTE_MULTILINE);
    text->SetDefaultStyle(wxTextAttr(*wxRED));
    text->AppendText(wxT("Texte Rouge\n"));
    text->SetDefaultStyle(wxTextAttr(wxNullColour, *wxGREEN,*wxITALIC_FONT, \
                                     wxTEXT_ALIGNMENT_CENTRE));
    text->AppendText(wxT(“En italic et centré sur Fond Vert\n"));
    text->SetDefaultStyle(wxTextAttr(*wxBLUE,*wxWHITE,*wxSMALL_FONT, \
                                     wxTEXT_ALIGNMENT_RIGHT));
    text->SetDefaultStyle(wxTextAttr(*wxBLUE));
    text->AppendText(wxT(“Bleu et petit à droite\n"));

    Déclaration d’un contrôle de texte dans une fenêtre

    2.6 Les arbres : wxTreeCtrl

    Il s’agit d’un composant permettant de représenter des données sous la forme d’une arborescence. Le plus connu étant la lecture d’un fichier à l’aide d’une boîte de dialogue.
    On peut réduire ou étendre les objets contenus dans une branche. Ce contrôle est utilisé notamment pour afficher des informations dans des projets.

    /img-articles/lm/83/cc-art-wxwidget/fig-6.jpg

    Fig. 4 : wxTreeCtrl, un arbre simple

    Il s’agit d’un composant complexe offrant de nombreuses possibilités. Nous ne verrons ici qu’un exemple simple. Le code pour la figure 4 affiche uniquement du texte, mais il est possible d’ajouter des images et de les sélectionner.
    Il permet d’avoir plusieurs images suivant que l’élément est sélectionné ou non. Le fameux glisser-lâcher (ou drag’n’drop) est aussi présent. Bref, il faudrait consacrer un article entier à ce contrôle tellement il est vaste. Pour s’en convaincre, il suffit juste de savoir qu’il ne génère pas moins de 21 événements, sans compter les événements classiques à tous les contrôles. Le code générant la figure 4 est le suivant :

     

    #include <wx/treectrl.h> // include dans la fichier
    wxTreeCtrl* tree=new wxTreeCtrl(frame,wxID_ANY,wxPoint(10,10),wxSize(200,150));
    wxTreeItemId rootID=tree->AddRoot(wxT("Un arbre"));
    for (int i=0;i<10;i++)
    {
      wxTreeItemId id=tree->AppendItem(rootID,wxString::Format(wxT("Element : %d"),i+1));
      for(int j=0;j<2*i+2;j++)
        tree->AppendItem(id,wxString::Format(wxT("Element : %d:%d"),i+1,j+1));
    }

    Déclaration d’un contrôle de texte dans une fenêtre

    Chaque élément ou branche est caractérisé par un identificateur de type wxTreeItemId.
    Il faut en premier lieu créer l’élément racine et uniquement ensuite il est possible d’ajouter des branches sur lesquelles on peut aussi ajouter des ramifications.
    Lorsque l’on déploie une branche, un événement est généré (il n’est pas utilisé dans cet exemple).

    2.7 Le calendrier : wxCalendarCtrl

    /img-articles/lm/83/cc-art-wxwidget/fig-7.jpg

    Fig. 5 : wxCalendarCtrl, un calendrier

    Il s’agit d’un composant permettant la sélection d’une date. Un événement de sélection d’une table peut être récupéré à l’aide de la macro EVT_CALENDAR_SEL_CHANGED(id, func) avec id l’identificateur du calendrier et func la méthode permettant de traiter le changement de date.
    Il suffit ensuite d’utiliser la méthode GetDate() qui renvoie un élément de type wxDateTime pour connaître la nouvelle date.
    Des fonctionnalités telles que : changement de couleur sur les jours fériés, les vacances... existent. Pour obtenir la figure 5, il suffit d’écrire le code suivant :

    wxCalendarCtrl* calendar=new wxCalendarCtrl(frame,wxID_ANY,wxDefaultDateTime,wxPoint(5,5),wxSize(200,150));

    Déclaration d’un élément de type wxCalendarCtrl pour obtenir une date

    Un composant prenant moins de place existe : il s’agit de wxDatePickerCtrl.
    L’avantage est que seule la date sélectionnée est affichée et un composant s’ouvre lors de la sélection et se referme ensuite : une sorte de pseudo boîte de dialogue de la même façon que la ComboBox.

    2.8 Les boutons à cocher : wxRadioButton

    Il s’agit d’un composant permettant de sélectionner de façon exclusive une option (en général).
    Pour cela, le premier wxRadioButton doit être du type wxRB_GROUP et tous les boutons créés sont ensuite considérés comme faisant partie du groupe.

    /img-articles/lm/83/cc-art-wxwidget/fig-9.jpg

     

    Fig. 6 : Boîte de boutons à cocher

    Le groupe s’arrête si un bouton de type wxRB_GROUP est de nouveau créé. La récupération de l’événement wxEVT_COMMAND_RADIOBUTTON_SELECTED à l’aide de la macro EVT_RADIOBUTTON(id, func) permet de détecter un changement de valeur. Le code permettant d’obtenir la figure 6 est alors le suivant :

    wxRadioButton* radio;
    radio=new wxRadioButton(frame,wxID_ANY,wxT("Element : 1"), \
                            wxPoint(5,5),wxSize(100,30),wxRB_GROUP);
    for(int i=2;i<=5;i++)
      radio=new wxRadioButton(frame,wxID_ANY,wxString::Format(wxT("Element %d :"),i),\
                              wxPoint(5,5+30*i-30),wxSize(100,30));

     

    Déclaration de plusieurs boutons à cocher : wxRadioButton en sélection exclusive

    La variable radio ne sert à rien ici et un simple new suffit amplement, car les éléments sont des contrôles enfants de la fenêtre donc il n’y a pas de fuites de mémoire lors de la fermeture de l’application.

    2.9 Les groupes de boutons à cocher : wxRadioBox

    /img-articles/lm/83/cc-art-wxwidget/fig-9.jpg

     

    Fig. 7 : Boîte de boutons à cocher

    Il s’agit d’un composant spécifique dédié à la sélection exclusive. Il a en général la préférence des utilisateurs, car il est entouré d’un cadre et sa création est simplifiée par rapport à l’exemple précédent. La récupération de l’événement wxEVT_COMMAND_RADIOBOX_SELECTED à l’aide de la macro EVT_RADIOBOX(id, func) permet de récupérer un changement de valeur.
    L’avantage de ce cadre, en plus de l’intérêt esthétique, est de pouvoir autoriser ou non une sélection dans le groupe. Le code permettant d’obtenir la figure 7 est alors le suivant :

    wxString tab[5];
    for(int i=1;i<=5;i++) tab[i-1]=wxString::Format(wxT("Element : %d"),i);
    wxRadioBox* radiobox=new wxRadioBox(frame,wxID_ANY,wxT("Un choix"),\
                                  wxPoint(5,5),wxSize(100,150),5,tab);

    Déclaration d’une boîte de sélection exclusive à l’aide d’un contrôle wxRadioBox

    Il est aussi possible de changer l’orientation des boutons de façon simple : en modifiant le code, on peut obtenir simplement 3 boutons par ligne. On a alors le résultat de la figure 8 :

    /img-articles/lm/83/cc-art-wxwidget/fig-10.jpg

    Fig. 8 : wxRadioBox* radiobox=new wxRadioBox(frame,wxID_ANY,wxT("Un choix"),wxPoint(5,5),wxSize(300,80),5,tab,3);

    2.10 La sélection d’une valeur par glissement : wxSlider

    /img-articles/lm/83/cc-art-wxwidget/fig-11.jpg

    Fig. 8 : Une sélection par curseur : wxSlider

    Il s’agit d’un composant permettant de sélectionner de façon graphique une valeur. On le retrouve dans le réglage des couleurs, du volume...
    Il permet de fixer la valeur basse et haute sans avoir besoin de vérifier si les limites sont dépassées. Il est aussi possible de bouger le curseur en utilisant les touches [FLECHE GAUCHE] [FLECHE DROITE] [FLECHE BAS] [FLECHE HAUT], [DEBUT], [FIN] ou même [PAGE HAUT] [PAGE BAS] en plus de la souris.
    Les tailles des déplacements peuvent alors être fixées dans le composant. Le code de la figure 8 est :

     

    wxSlider* slider=new wxSlider(frame,wxID_ANY,30,20,100,wxPoint(5,5),wxSize(130,20));

    Déclaration d’un glisseur : wxSlider

    La récupération de la valeur se fait avec la méthode GetValue(). Différents événements de type wxScrollEvent sont générés lors des déplacements.
    Ils peuvent être récupérés par l’utilisation de la macro EVT_SCROLL(func). D’autres macros permettant la distinction du type d’événements existent (ex : EVT_SCROLL_LINEUP).

    Conclusion

    Cette troisième partie a permis de découvrir un certain nombre de widgets. Il en reste encore quelques-uns, mais avec ceux décrits ici il y a déjà matière à réalisation. Cependant, la façon expliquée ici pour les placer dans une fenêtre (ou dans un panneau) n’est pas satisfaisante, car il s’agit d’un placement fixe, statique : si la taille de la fenêtre varie (ou si vous avez acheté un plus grand écran), la place récupérée doit pouvoir être utilisée de façon simple par les contrôles. La méthode employée sera de laisser le calcul des nouvelles positions et tailles (lors d’un changement de taille) à des composants liés aux différents contrôles. Il y a pour cela deux techniques qui seront abordées dans une prochaine partie.

    Liens

    Posté par (La rédaction) | Signature : olivier corrio | Article paru dans Creative Commons License

    Laissez une réponse

    Vous devez avoir ouvert une session pour écrire un commentaire.