Exemple d'assistant de licence
L'exemple « Assistant de licence » montre comment implémenter des assistants complexes dans Qt.

La plupart des assistants ont une structure linéaire : la page 1 est suivie de la page 2, et ainsi de suite jusqu'à la dernière page. L'exemple « Trivial Wizard » montre comment créer ce type d'assistants.
Certains assistants sont plus complexes dans la mesure où ils permettent différents parcours en fonction des informations fournies par l'utilisateur. L'exemple « Assistant de licence » illustre ce principe. Il propose plusieurs pages d'assistant ; selon les options sélectionnées, l'utilisateur peut accéder à différentes pages.

L'exemple se compose des classes suivantes :
LicenseWizardhérite de ` QWizard ` et implémente un assistant non linéaire de cinq pages qui guide l'utilisateur tout au long du processus de sélection d'un contrat de licence.IntroPage,EvaluatePage,RegisterPage,DetailsPageetConclusionPagesont des sous-classes d’ QWizardPage qui implémentent les pages de l’assistant.
La classe LicenseWizard
La classe LicenseWizard dérive de QWizard et fournit un assistant de cinq pages qui guide l’utilisateur tout au long du processus d’enregistrement de son exemplaire d’un logiciel fictif. Voici la définition de la classe :
class LicenseWizard : public QWizard
{
Q_OBJECT
public:
enum { Page_Intro, Page_Evaluate, Page_Register, Page_Details,
Page_Conclusion };
LicenseWizard(QWidget *parent = nullptr);
private slots:
void showHelp();
};L'API publique de la classe se limite à un constructeur et à une énumération. L’énumération définit les identifiants associés aux différentes pages :
| Nom de la classe | Valeur de l'énumération | ID de la page |
|---|---|---|
IntroPage | Page_Intro | 0 |
EvaluatePage | Page_Evaluate | 1 |
RegisterPage | Page_Register | 2 |
DetailsPage | Page_Details | 3 |
ConclusionPage | Page_Conclusion | 4 |
Dans cet exemple, les identifiants sont arbitraires. Les seules contraintes sont qu'ils doivent être uniques et différents de -1. Les identifiants permettent de faire référence à des pages.
LicenseWizard::LicenseWizard(QWidget *parent)
: QWizard(parent)
{
setPage(Page_Intro, new IntroPage);
setPage(Page_Evaluate, new EvaluatePage);
setPage(Page_Register, new RegisterPage);
setPage(Page_Details, new DetailsPage);
setPage(Page_Conclusion, new ConclusionPage);
setStartId(Page_Intro);Dans le constructeur, nous créons les cinq pages, les insérons dans l’assistant à l’aide de ` QWizard::setPage()` et définissons ` Page_Intro ` comme première page.
#ifndef Q_OS_MACOS
setWizardStyle(ModernStyle);
#endifNous définissons le style « ModernStyle » sur toutes les plateformes sauf macOS,
setOption(HaveHelpButton, true);
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo.png"));
connect(this, &QWizard::helpRequested, this, &LicenseWizard::showHelp);
setWindowTitle(tr("License Wizard"));
}Nous configurons l’ QWizard pour qu’il affiche un bouton « Help », qui est relié à notre slot « showHelp() ». Nous définissons également l’ LogoPixmap pour toutes les pages comportant un en-tête (à savoir : EvaluatePage, RegisterPage et DetailsPage).
void LicenseWizard::showHelp()
{
static QString lastHelpMessage;
QString message;
switch (currentId()) {
case Page_Intro:
message = tr("The decision you make here will affect which page you "
"get to see next.");
break;
...
default:
message = tr("This help is likely not to be of any help.");
}
if (lastHelpMessage == message)
message = tr("Sorry, I already gave what help I could. "
"Maybe you should try asking a human?");
QMessageBox::information(this, tr("License Wizard Help"), message);
lastHelpMessage = message;
}Dans showHelp(), nous affichons des textes d’aide adaptés à la page actuelle. Si l’utilisateur clique deux fois sur Help pour la même page, nous lui répondons : « Désolé, je vous ai déjà donné toute l’aide possible. Vous devriez peut-être essayer de demander à un humain ? »
La classe IntroPage
Les pages sont définies dans licensewizard.h et implémentées dans licensewizard.cpp, ainsi que dans LicenseWizard.
Voici la définition et l’implémentation de ` IntroPage` :
class IntroPage : public QWizardPage
{
Q_OBJECT
public:
IntroPage(QWidget *parent = nullptr);
int nextId() const override;
private:
QLabel *topLabel;
QRadioButton *registerRadioButton;
QRadioButton *evaluateRadioButton;
};
IntroPage::IntroPage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Introduction"));
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark.png"));
topLabel = new QLabel(tr("This wizard will help you register your copy of "
"<i>Super Product One</i>™ or start "
"evaluating the product."));
topLabel->setWordWrap(true);
registerRadioButton = new QRadioButton(tr("&Register your copy"));
evaluateRadioButton = new QRadioButton(tr("&Evaluate the product for 30 "
"days"));
registerRadioButton->setChecked(true);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(topLabel);
layout->addWidget(registerRadioButton);
layout->addWidget(evaluateRadioButton);
setLayout(layout);
}Une page hérite de QWizardPage. Nous définissons un title et un watermark pixmap. En ne définissant aucun subTitle, nous nous assurons qu’aucun en-tête ne s’affiche pour cette page. (Sous Windows, il est d’usage que les assistants affichent un filigrane sous forme d’image pixmap sur la première et la dernière page, et qu’ils comportent un en-tête sur les autres pages.)
int IntroPage::nextId() const
{
if (evaluateRadioButton->isChecked()) {
return LicenseWizard::Page_Evaluate;
} else {
return LicenseWizard::Page_Register;
}
}La fonction ` nextId() ` renvoie l’ID de ` EvaluatePage ` si l’option ` Evaluate the product for 30 days ` est cochée ; sinon, elle renvoie l’ID de ` RegisterPage`.
La classe EvaluatePage
La méthode EvaluatePage est un peu plus complexe :
class EvaluatePage : public QWizardPage
{
Q_OBJECT
public:
EvaluatePage(QWidget *parent = nullptr);
int nextId() const override;
private:
QLabel *nameLabel;
QLabel *emailLabel;
QLineEdit *nameLineEdit;
QLineEdit *emailLineEdit;
};
EvaluatePage::EvaluatePage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Evaluate <i>Super Product One</i>™"));
setSubTitle(tr("Please fill both fields. Make sure to provide a valid "
"email address (e.g., john.smith@example.com)."));
nameLabel = new QLabel(tr("N&ame:"));
nameLineEdit = new QLineEdit;
...
registerField("evaluate.name*", nameLineEdit);
registerField("evaluate.email*", emailLineEdit);
...
}Tout d’abord, nous définissons les propriétés ` title ` et ` subTitle` de la page.
Ensuite, nous créons les widgets enfants, créons les wizard fields qui leur sont associés, puis les plaçons dans des mises en page. Les champs sont créés avec un astérisque (*) à côté de leur nom. Cela en fait des mandatory fields, c’est-à-dire des champs qui doivent être renseignés avant que l’utilisateur puisse cliquer sur le bouton « Next » (Continue sous macOS). Les valeurs de ces champs sont accessibles depuis n’importe quelle autre page à l’aide de QWizardPage::field().
La réinitialisation de la page revient à vider les deux champs de texte.
int EvaluatePage::nextId() const
{
return LicenseWizard::Page_Conclusion;
}La page suivante est toujours « ConclusionPage ».
La classe ConclusionPage
Les méthodes RegisterPage et DetailsPage sont très similaires à celles de EvaluatePage. Passons directement à la méthode ConclusionPage:
class ConclusionPage : public QWizardPage
{
Q_OBJECT
public:
ConclusionPage(QWidget *parent = nullptr);
void initializePage() override;
int nextId() const override;
void setVisible(bool visible) override;
private slots:
void printButtonClicked();
private:
QLabel *bottomLabel;
QCheckBox *agreeCheckBox;
};Cette fois-ci, nous réimplémentons QWizardPage::initializePage() et QWidget::setVisible(), en plus de nextId(). Nous déclarons également un slot privé : printButtonClicked().
int IntroPage::nextId() const
{
if (evaluateRadioButton->isChecked()) {
return LicenseWizard::Page_Evaluate;
} else {
return LicenseWizard::Page_Register;
}
}L’implémentation par défaut de ` QWizardPage::nextId()` renvoie la page ayant l’ID suivant, ou -1 si la page actuelle possède l’ID le plus élevé. Ce comportement fonctionnerait ici, car ` Page_Conclusion ` est égal à 5 et il n’existe aucune page avec un ID supérieur, mais pour éviter de nous fier à un comportement aussi subtil, nous réimplémentons ` nextId()` pour qu’il renvoie -1.
void ConclusionPage::initializePage()
{
QString licenseText;
if (wizard()->hasVisitedPage(LicenseWizard::Page_Evaluate)) {
licenseText = tr("<u>Evaluation License Agreement:</u> "
"You can use this software for 30 days and make one "
"backup, but you are not allowed to distribute it.");
} else if (wizard()->hasVisitedPage(LicenseWizard::Page_Details)) {
const QString emailAddress = field("details.email").toString();
licenseText = tr("<u>First-Time License Agreement:</u> "
"You can use this software subject to the license "
"you will receive by email sent to %1.").arg(emailAddress);
} else {
licenseText = tr("<u>Upgrade License Agreement:</u> "
"This software is licensed under the terms of your "
"current license.");
}
bottomLabel->setText(licenseText);
}Nous utilisons QWizard::hasVisitedPage() pour déterminer le type de contrat de licence choisi par l’utilisateur. Si l’utilisateur a renseigné le champ EvaluatePage, le texte de la licence fait référence à un contrat de licence d’évaluation. Si l’utilisateur a renseigné le champ DetailsPage, le texte de la licence correspond à un contrat de licence de première utilisation. Si l’utilisateur a fourni une clé de mise à niveau et a ignoré le champ DetailsPage, le texte de la licence correspond à un contrat de licence de mise à jour.
void ConclusionPage::setVisible(bool visible)
{
QWizardPage::setVisible(visible);
if (visible) {
wizard()->setButtonText(QWizard::CustomButton1, tr("&Print"));
wizard()->setOption(QWizard::HaveCustomButton1, true);
connect(wizard(), &QWizard::customButtonClicked,
this, &ConclusionPage::printButtonClicked);
} else {
wizard()->setOption(QWizard::HaveCustomButton1, false);
disconnect(wizard(), &QWizard::customButtonClicked,
this, &ConclusionPage::printButtonClicked);
}
}Nous souhaitons afficher un bouton « Print » dans l’assistant lorsque la page ConclusionPage est active. Pour ce faire, nous pouvons notamment réimplémenter la méthode QWidget::setVisible() :
- Si la page est affichée, nous définissons le texte du bouton « CustomButton1 » sur Print, nous activons l’option « HaveCustomButton1 » et nous connectons le signal customButtonClicked() de l’ QWizard à notre slot
printButtonClicked(). - Si la page est masquée, nous désactivons l’option « HaveCustomButton1 » et déconnectons le slot
printButtonClicked().
Voir également QWizard et Exemple d'assistant trivial.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.