Главная · Все классы · Основные классы · Классы по группам · Модули · Функции

Пример "License Wizard"

Файлы:

Пример "License Wizard" показывает, как реализовывать сложные мастера в Qt.

Снимок экрана примера "License Wizard"

Многие мастера имеют линейную структуру, со страницей 1, следом - страница 2 и так далее до последней страницы. Пример "Class Wizard" показывает как создавать такие мастера.

Некоторые более сложные мастера, в которых разрешены разные пути прохождения на основе информации, предоставляемой пользователем. Пример "License Wizard" это иллюстрирует. Он предоставляет пять страниц мастера; в зависимости от выбранных опций пользовтель может достигать разных страниц.

Страницы мастера лицензий

Пример состоит из следующих классов:

Класс LicenseWizard

Класс LicenseWizard унаследован от QWizard и предоставляет пятистраничный мастер, который проведёт пользователя по процессу регистрации его копии выдуманного программного продукта. Вот определение класса:

 class LicenseWizard : public QWizard
 {
     Q_OBJECT

 public:
     enum { Page_Intro, Page_Evaluate, Page_Register, Page_Details,
            Page_Conclusion };

     LicenseWizard(QWidget *parent = 0);

 private slots:
     void showHelp();
 };

Открытый API класса ограничен конструктором и перечислением. Перечисление определяет идентификаторы, связанные с разными страницами:

Имя классаЗначение перечисленияИдентификатор страницы
IntroPagePage_Intro0
EvaluatePagePage_Evaluate1
RegisterPagePage_Register2
DetailsPagePage_Details3
ConclusionPagePage_Conclusion4

Для этого примера идентификаторы являются произвольными. Единственными ограничениями является то, что они должны быть уникальными и отличным от -1. Идентификаторы позволяют нам ссылать на страницы.

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

В конструкторе мы создаём пять страниц, вставляет их в мастер, используя QWizard::setPage(), и устанавливаем Page_Intro первой страницей.

 #ifndef Q_WS_MAC
     setWizardStyle(ModernStyle);
 #endif

Мы установили стиль ModernStyle на всех платформах, за исключением Mac OS X,

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

     connect(this, SIGNAL(helpRequested()), this, SLOT(showHelp()));

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

Мы конфигурируем QWizard чтобы показать кнопку Help, которая соединена с нашим слотом showHelp(). Мы также установили LogoPixmap для всех страниц, у которых есть заголовок (т.е., EvaluatePage, RegisterPage и 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;
 }

В showHelp() мы выводим на экран справочные тексты, которые соответствуют текущей странице. Если пользователь дважды щелкнет Help на одной и той же странице, мы сообщим: "Sorry, I already gave what help I could. Maybe you should try asking a human?"

Класс IntroPage

Страницы определены в licensewizard.h и реализованы в licensewizard.cpp, вместе с LicenseWizard.

Вот определение и реализация IntroPage:

 class IntroPage : public QWizardPage
 {
     Q_OBJECT

 public:
     IntroPage(QWidget *parent = 0);

     int nextId() const;

 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. Мы установили title и watermark pixmap. Не устанавливая любой subTitle мы обеспечиваем, что для этой страницы не будет показан заголовок. (В Windows это обычно для мастеров - показывать растровое изображение водяного знака на первой и последней страницах, а на остальных страницах иметь заголовок.)

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

Функция nextId() возвращает идентификатор для EvaluatePage если отмечена опция Evaluate the product for 30 days; в противном случае она возвращает идентификатор RegisterPage.

Класс EvaluatePage

EvaluatePage немного более запутан:

 class EvaluatePage : public QWizardPage
 {
     Q_OBJECT

 public:
     EvaluatePage(QWidget *parent = 0);

     int nextId() const;

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

Сначала мы установили title и subTitle страницы.

Затем мы создаём дочерние виджеты, создаём поля мастера, связанные с ними, и помещаем их в компоновки. Поля создаются с символом звездочка (*) после их имён. Это делает их обязательными полями, т.е., поля, которые должны быть заполнены до того как пользователь сможет нажать кнопку Next (Continue в Mac OS X). Значения полей доступны из любой другой страницы с использованием QWizardPage::field().

Сбросим количество страниц для очистки двух текстовых полей.

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

Следующая страница - всегда ConclusionPage.

Класс ConclusionPage

RegisterPage и DetailsPage очень похожи на EvaluatePage. Давайте перейдём непосредственно к ConclusionPage:

 class ConclusionPage : public QWizardPage
 {
     Q_OBJECT

 public:
     ConclusionPage(QWidget *parent = 0);

     void initializePage();
     int nextId() const;
     void setVisible(bool visible);

 private slots:
     void printButtonClicked();

 private:
     QLabel *bottomLabel;
     QCheckBox *agreeCheckBox;
 };

Сейчас мы повторно реализуем QWizardPage::initializePage() и QWidget::setVisible(), в дополнение к nextId(). Мы также объявляем закрытый слот: printButtonClicked().

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

Реализация QWizardPage::nextId() по умолчанию возвращает страницу со следующим идентификатором или -1, если текущая страница имеет наибольший идентификатор. Это поведение будет работать здесь, поскольку Page_Conclusion равно 5 и нет страниц с большим идентификатором, но чтобы не полагаться на такое тонкое поведение, мы повторно реализуем nextId() для возвращения -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)) {
         licenseText = tr("<u>First-Time License Agreement:</u> "
                          "You can use this software subject to the license "
                          "you will receive by email.");
     } 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, текст лицензии ссылается на Evaluation License Agreement. Если пользователь заполнил DetailsPage, текст лицензии - First-Time License Agreement. Если пользователь предоставил ключ модернизации и пропустил DetailsPage, текст лицензии - Update License Agreement.

 void ConclusionPage::setVisible(bool visible)
 {
     QWizardPage::setVisible(visible);

     if (visible) {
         wizard()->setButtonText(QWizard::CustomButton1, tr("&Print"));
         wizard()->setOption(QWizard::HaveCustomButton1, true);
         connect(wizard(), SIGNAL(customButtonClicked(int)),
                 this, SLOT(printButtonClicked()));
     } else {
         wizard()->setOption(QWizard::HaveCustomButton1, false);
         disconnect(wizard(), SIGNAL(customButtonClicked(int)),
                    this, SLOT(printButtonClicked()));
     }
 }

Мы хотим вывести на экран кнопку Print в мастере когда открыта ConclusionPage. Один способ чтобы достигнуть этого - повторно реализовать QWidget::setVisible():

Смотрите также QWizard, Пример "Class Wizard" и Пример "Trivial Wizard".


Copyright © 2008 Trolltech Торговые марки
Qt 4.3.5