ライセンスウィザードの例

ライセンス・ウィザードの例は、Qtで複雑なウィザードを実装する方法を示しています。

Screenshot of the License Wizard example

ほとんどのウィザードは、1ページ目の後に2ページ目が続き、最終ページまで続く直線的な構造になっています。Trivial Wizardの例では、そのようなウィザードの作成方法を示します。

ウィザードの中には、ユーザーによって提供された情報に基づいて、異なるトラバーサル・パスを許可する複雑なものもあります。ライセンス・ウィザードの例は、これを示しています。これは複数のウィザード・ページを提供し、選択されたオプションに応じて、ユーザは異なるページに到達することができます。

The License Wizard pages

この例は、以下のクラスで構成されています:

  • LicenseWizard QWizard を継承し、ユーザーをライセンス契約の選択プロセスへと導く、5 ページのノンリニアウィザードを実装しています。
  • IntroPage EvaluatePage 、 、 、 は、ウィザード・ページを実装する サブクラスです。RegisterPage DetailsPage ConclusionPage QWizardPage

LicenseWizard クラス

LicenseWizard クラスはQWizard から派生したもので、架空のソフトウェア製品のコピーの登録プロセスを通じてユーザーをガイドする 5 ページのウィザードを提供します。クラスの定義は次のとおりです:

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();
};

このクラスのパブリックAPIはコンストラクタと列挙型に限られています。列挙型は、さまざまなページに関連するIDを定義します:

クラス名列挙値ページID
IntroPagePage_Intro0
EvaluatePagePage_Evaluate1
RegisterPagePage_Register2
DetailsPagePage_Details3
ConclusionPagePage_Conclusion4

この例では、IDは任意である。IDによってページを参照することができる。

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);

コンストラクタでは、5つのページを作成し、QWizard::setPage ()を使用してウィザードに挿入し、Page_Intro を最初のページに設定します。

#ifndef Q_OS_MAC
    setWizardStyle(ModernStyle);
#endif

macOS以外のプラットフォームでは、スタイルをModernStyle

    setOption(HaveHelpButton, true);
    setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo.png"));

    connect(this, &QWizard::helpRequested, this, &LicenseWizard::showHelp);

    setWindowTitle(tr("License Wizard"));
}

showHelp() スロットに接続されているHelp ボタンを表示するようにQWizard を設定します。また、ヘッダーを持つすべてのページ(すなわち、EvaluatePageRegisterPageDetailsPage )にLogoPixmap を設定します。

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;
}

showHelp() では、現在のページに適したヘルプテキストを表示します。もしユーザーが同じページに対してHelp を2回クリックした場合、「申し訳ありません、できる限りのヘルプはすでにしました。人間に尋ねてみてはいかがでしょうか?" と表示します。

IntroPageクラス

LicenseWizardページはlicensewizard.h で定義され、licensewizard.cpp で実装されています。

以下は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>&trade; 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);
}

ページはQWizardPage を継承します。titlewatermark pixmap を設定します。subTitle を設定しないことで、このページにヘッダーが表示されないようにしています。(Windowsでは、ウィザードは最初と最後のページに透かしのピクセルマップを表示し、他のページにはヘッダーを表示するのが通例です)。

int IntroPage::nextId() const
{
    if (evaluateRadioButton->isChecked()) {
        return LicenseWizard::Page_Evaluate;
    } else {
        return LicenseWizard::Page_Register;
    }
}

nextId() 関数は、Evaluate the product for 30 days オプションがチェックされていればEvaluatePage の ID を返し、チェックされていなければRegisterPage の ID を返します。

EvaluatePageクラス

EvaluatePage は少し複雑です:

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>&trade;"));
    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);
    ...
}

まず、ページのtitlesubTitle を設定します。

次に、子ウィジェットを作成し、それらに関連付けられたwizard fields を作成し、それらをレイアウトに配置します。フィールドは、名前の横にアスタリスク(*)を付けて作成します。mandatory fieldsつまり、ユーザがNext ボタン ( macOS ではContinue ) を押す前に入力しなければならないフィールドです。フィールドの値は、他のどのページからもQWizardPage::field()を使ってアクセスすることができる。

ページをリセットすることは、2つのテキスト・フィールドをクリアすることに等しい。

int EvaluatePage::nextId() const
{
    return LicenseWizard::Page_Conclusion;
}

次のページは常にConclusionPage

ConclusionPageクラス

RegisterPageDetailsPageEvaluatePage とよく似ています。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;
};

今回は、nextId() に加えて、QWizardPage::initializePage() とQWidget::setVisible() を再実装します。また、printButtonClicked() というプライベート・スロットを宣言します。

int IntroPage::nextId() const
{
    if (evaluateRadioButton->isChecked()) {
        return LicenseWizard::Page_Evaluate;
    } else {
        return LicenseWizard::Page_Register;
    }
}

QWizardPage::nextId() のデフォルトの実装は、次のIDを持つページを返し、現在のページが最も高いIDを持つ場合は-1を返す。この動作は、Page_Conclusion が 5に等しく、それより大きいIDを持つページが存在しないため、ここでも機能するが、そのような微妙な動作に依存することを避けるため、-1を返すようにnextId() を再実装する。

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);
}

QWizard::hasVisitedPage()を使用して、ユーザーが選択したライセンス契約のタイプを判断する。ユーザーがEvaluatePage を入力した場合、ライセンス・テキストは評価ライセンス契約を参照する。ユーザーがDetailsPage に記入した場合、ライセンステキストは初回ライセンス契約です。ユーザーがアップグレードキーを提供し、DetailsPage をスキップした場合、ライセンステキストは更新ライセンス契約です。

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);
    }
}

ConclusionPage 、ウィザードにPrint 。これを実現する1つの方法は、QWidget::setVisible ()を再実装することです:

  • ページが表示されたら、CustomButton1 ボタンのテキストを Printページが表示されている場合、QWizard ボタンのテキストを設定し、HaveCustomButton1 オプションを有効にし、 'のcustomButtonClicked() シグナルをprintButtonClicked() スロットに接続します。
  • ページが非表示の場合は、HaveCustomButton1 オプションを無効にし、printButtonClicked() スロットを切断します。

プロジェクト例 @ code.qt.io

QWizard およびTrivial Wizard Exampleも参照してください

© 2025 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.