// C / C++

Introduction à wxWidgets : des GUI natives en C++

Écrire une interface graphique en C++ qui a l’air native sur Windows, macOS et Linux à partir d’un seul code source : c’est exactement la promesse de wxWidgets. Contrairement à des bibliothèques qui dessinent leurs propres widgets, wxWidgets utilise les composants réels de chaque système d’exploitation. Une fenêtre ressemble donc à une vraie fenêtre Windows sous Windows, et à une fenêtre Cocoa sous macOS. Ce tutoriel pose les fondations : structure d’une application, wxFrame, événements et compilation.

Pourquoi choisir wxWidgets ?

wxWidgets est un projet ancien, robuste et toujours activement maintenu. Ses arguments restent solides :

  • Rendu natif : les boutons, menus et boîtes de dialogue sont ceux du système. L’application se fond dans l’environnement de l’utilisateur.
  • Multiplateforme : un même code compile sous les trois grands systèmes de bureau.
  • Licence permissive : on peut l’utiliser dans des logiciels propriétaires sans contrainte lourde.
  • Complet : au-delà des widgets, il fournit des classes pour les fichiers, les threads, le réseau ou les images.

C’est un choix pertinent quand on veut un logiciel de bureau classique en C++, sans embarquer un moteur de rendu volumineux.

Installer la bibliothèque

Sous Linux, le paquet de développement est disponible dans la plupart des distributions :

# Debian / Ubuntu
sudo apt install libwxgtk3.2-dev

Sous Windows, on récupère les binaires précompilés sur le site officiel, ou l’on compile les sources avec Visual Studio. Sous macOS, Homebrew propose brew install wxwidgets. Dans tous les cas, l’outil wx-config (ou son équivalent) vous donnera plus tard les bons drapeaux de compilation.

L’architecture d’une application wxWidgets

Une application wxWidgets s’articule toujours autour de deux classes que vous dérivez :

  1. La classe application, héritée de wxApp. Elle représente le programme lui-même et possède une méthode OnInit appelée au démarrage — c’est l’équivalent conceptuel du main.
  2. La classe fenêtre, généralement héritée de wxFrame. Une frame est une fenêtre de premier niveau avec barre de titre, bordures, menu éventuel et zone cliente.

La macro wxIMPLEMENT_APP génère le vrai point d’entrée et lance la boucle d’événements à votre place.

Un exemple minimal

Voici une application complète qui ouvre une fenêtre. Détaillons-la ensuite.

#include <wx/wx.h>

// La fenêtre principale
class MaFenetre : public wxFrame {
public:
    MaFenetre()
        : wxFrame(nullptr, wxID_ANY, "Bonjour Coder Studio",
                  wxDefaultPosition, wxSize(400, 300)) {
        wxButton* bouton = new wxButton(this, wxID_ANY, "Cliquez-moi",
                                        wxPoint(140, 120));
        // On lie l'événement du bouton à une méthode
        bouton->Bind(wxEVT_BUTTON, &MaFenetre::OnClic, this);
    }

private:
    void OnClic(wxCommandEvent&) {
        wxMessageBox("Bouton cliqué !", "Info",
                     wxOK | wxICON_INFORMATION);
    }
};

// La classe application
class MonApp : public wxApp {
public:
    bool OnInit() override {
        MaFenetre* fenetre = new MaFenetre();
        fenetre->Show(true);
        return true;
    }
};

wxIMPLEMENT_APP(MonApp);

Décryptage du code

Plusieurs éléments méritent qu’on s’y arrête.

Le constructeur de MaFenetre appelle celui de wxFrame avec un parent (nullptr, car c’est la fenêtre racine), un identifiant (wxID_ANY laisse wxWidgets en attribuer un), un titre, une position et une taille. C’est le schéma classique de tout widget wxWidgets : on précise son parent, puis ses propriétés.

Le bouton est créé avec new et prend this comme parent — il appartient donc à la fenêtre, qui le détruira automatiquement. On ne libère pas soi-même les widgets enfants : wxWidgets gère leur cycle de vie via la hiérarchie parent-enfant.

Dans OnInit, on instancie la fenêtre et on l’affiche avec Show. Retourner true indique que l’initialisation a réussi et que la boucle d’événements peut démarrer.

La gestion des événements

Le cœur d’une interface, c’est de réagir aux actions de l’utilisateur. wxWidgets propose pour cela la méthode Bind, qui relie un type d’événement à une fonction membre.

bouton->Bind(wxEVT_BUTTON, &MaFenetre::OnClic, this);

On lit cette ligne ainsi : « quand ce bouton émet l’événement wxEVT_BUTTON (un clic), appelle la méthode OnClic de l’objet this ». La fonction reçoit un wxCommandEvent& décrivant l’événement. Cette approche dynamique est la façon moderne de connecter les événements ; les anciennes versions utilisaient des tables d’événements statiques que vous rencontrerez peut-être encore dans du code existant.

Compiler le programme

C’est ici que wx-config simplifie la vie. Il fournit les chemins d’en-têtes et les bibliothèques à lier. Sous Linux ou macOS :

g++ app.cpp `wx-config --cxxflags --libs` -o app
./app

Les accents graves exécutent wx-config et insèrent son résultat dans la ligne de commande. Sous Windows avec Visual Studio, on configure plutôt les répertoires d’inclusion et les bibliothèques dans les propriétés du projet, ou l’on s’appuie sur un système de build comme CMake, qui détecte wxWidgets et gère ces réglages automatiquement — l’option recommandée pour un projet sérieux.

Où aller ensuite ?

Vous tenez le squelette d’une vraie application de bureau. Les étapes suivantes consistent à disposer les widgets avec des sizers (plutôt que des positions fixes en pixels), à ajouter une barre de menus et une barre d’état, puis à explorer les nombreux contrôles disponibles : listes, arbres, onglets, tableaux. La logique reste la même : créer un widget avec son parent, puis connecter ses événements.

À lire ensuite

  • Solidifiez vos bases avec notre guide du langage C, fondation du C++.
  • Ne fuyez jamais une ressource grâce au RAII en C++, essentiel en programmation GUI.
  • Découvrez une autre bibliothèque GUI multiplateforme avec GTK en Haskell.