The Wizard Magically Reappears

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(перевод в движении)
(немного перевёл)
 
(13 промежуточных версий не показаны.)
Строка 3: Строка 3:
by Jo Asplin
by Jo Asplin
-
'''После исчезновения в клубах дыма, с выходом Qt4, QWizard сново часть Qt. QWizard и его нвоый подмастерье, QWizardPage, отработавшие свое краткое время в Qt4 Solutions, и теперь насыщенные возможностями, которые сделают работу програмиста мастеров легче, чем когда либо.'''
+
'''После исчезновения в клубах дыма, с выходом Qt4, QWizard сново часть Qt. QWizard и его новый подмастерье - QWizardPage, отработавшие свое краткое время в Qt4 Solutions, и теперь насыщенные возможностями, которые сделают работу програмиста мастеров легче, чем когда либо.'''
__TOC__
__TOC__
-
[[Qt:Документация_4.3.2/qwizard  | QWizard]] provides a framework for writing wizards (also calledassistants). The purpose of a wizard is to guide the user through aprocess step by step. Compared with the [[Qt:Документация_4.3.2/qwizard  | QWizard]] class foundin Qt 3 and the <tt>Q3Wizard</tt> compatibility class of Qt 4, the newwizard provides the following features:
+
[[Qt:Документация_4.3.2/qwizard  | QWizard]] предоставляет каркас для написания мастеров (wizard). Цель мастера - провести пользователя через процесс шаг за шагом. Сравнивая класс [[Qt:Документация_4.3.2/qwizard  | QWizard]] предоставляемый Qt 3 и класс совместимости <tt>Q3Wizard</tt> из Qt 4, новый мастер предоствляет следующие особенности:
-
 
+
-
* '''A native look and feel on all platforms'''<br />[[Qt:Документация_4.3.2/qwizard  | QWizard]] supports four different looks &mdash; Classic (Windows 95 and X11), Modern(Windows 98 to XP), Aero (Windows Vista), and Mac (Mac OS X). By default,[[Qt:Документация_4.3.2/qwizard  | QWizard]] automatically chooses the most appropriate style for theuser's platform, but this can be overridden.<br />
+
 +
* '''Естественный внешний вид и поведение на всех платформах'''<br />[[Qt:Документация_4.3.2/qwizard  | QWizard]] supports four different looks &mdash; Classic (Windows 95 and X11), Modern(Windows 98 to XP), Aero (Windows Vista), and Mac (Mac OS X). By default,[[Qt:Документация_4.3.2/qwizard  | QWizard]] automatically chooses the most appropriate style for theuser's platform, but this can be overridden.<br />
[[Image:qq22-wizard-styles.png|center]]
[[Image:qq22-wizard-styles.png|center]]
-
* '''A more powerful and convenient API'''<br />The new API makes iteasy to enable or disable the '''Next''' and '''Finish''' buttonsbased on the dialog's contents, and to exchange information betweenpages.<br />
+
* '''Более мощьный и удобный API'''<br />The new API makes iteasy to enable or disable the '''Next''' and '''Finish''' buttonsbased on the dialog's contents, and to exchange information betweenpages.<br />
-
* '''Support for non-linear wizards'''<br />Non-linear wizards allow different traversal pathsbased on the information provided by the user. <br />
+
* '''Поддержка нелинейных мастеров'''<br />Non-linear wizards allow different traversal pathsbased on the information provided by the user. <br />
In this article, we will focus on the control and data flow aspectsof wizards: What happens when the user navigates between pages, whenis the user allowed to navigate between pages, and how do we accessdata on which to base these decisions?
In this article, we will focus on the control and data flow aspectsof wizards: What happens when the user navigates between pages, whenis the user allowed to navigate between pages, and how do we accessdata on which to base these decisions?
-
===A Ferry Booking Example===
+
===Пример "Книга заказов парома"===
-
We will use a ferry trip booking wizard to illustrate a number ofthe concepts of the new wizard framework. The five pages involved areintentionally very simple: A page for selecting a sailing date, apage for entering the name of a single passenger, a page for choosinga cabin type, a page for specifying a car registration number in caseyou want to bring your car, and finally a page for entering a creditcard number.
+
Мы будем использовать мастер заказов паромной переправы, чтобы проилюстрировать различные концепции нового каркаса мастеров. Пять используемых страниц, умышленно сделаны очень простыми: Страница для выбора даты отплытия, страница для ввода имени единственного пассажира, страница для выбора типа каюты, страница для указания госномера автомобиля, в случае если вы хотите перевести ваш автомобиль и, наконец, страница ввода номера кредитной карты.
-
The following diagram depicts the possible navigation paths throughthe wizard:
+
Следующая диаграмма изображает возможные пути навигации с помощью мастера:
[[Image:qq22-ferryexample.png|center]]
[[Image:qq22-ferryexample.png|center]]
-
The initial implementation looks like this:
+
Исходная реализация выглядит подобно этой:
<source lang="cpp-qt">
<source lang="cpp-qt">
class BookingWizard : public QWizard
class BookingWizard : public QWizard
Строка 71: Строка 70:
}
}
</source>  
</source>  
-
The following code snippet shows how to open the wizard and collectresults from it:
+
Следующий фрагмент кода показывает как открыть мастер и собрать результаты из него:
<source lang="cpp-qt">
<source lang="cpp-qt">
BookingWizard wizard;
BookingWizard wizard;
Строка 81: Строка 80:
}
}
</source>  
</source>  
-
Notice how the <tt>BookingWizard</tt> class has to keep pointers to theinput widgets of all the pages in order to implement its publicinterface. In addition, if a page needs to access an input widget ofanother page, the pointer to the input widget would have to be passedto both pages.
+
Обратите внимание, как класс <tt>BookingWizard</tt> должен хранить указатели на виджеты ввода всех страниц для того, чтобы реализовать открытый интерфейс. Кроме того, если страница нуждается в доступе к виджету ввода с другой страницы, то указатель на виджет ввода должен быть передан обоим страницам.
-
 
+
===Регистрация и использование полей===
===Регистрация и использование полей===
-
To solve the problems identified above, we can use [[Qt:Документация_4.3.2/qwizard  | QWizard]]'sfield mechanism. A field consists of a widget instance, one of thewidget's properties (representing the value of the widget), thesignal to inform us about changes to the property (typically there isonly one such signal), and finally a name which must be unique withinthe wizard.
+
Чтобы решить проблему идентификации, указанную выше, мы можем использовать механизм полей [[Qt:Документация_4.3.2/qwizard  | QWizard]]'а. Поле состоит из из экземпляра объекта, одного из свойств виджета (представляющее значение виджета), сигнала информирующего нас об изменении свойства (обычно имеется только один такой сигнал) и, наконец, имя, которое должно быть уникальным в пределах мастера.
-
By referring to a field name and knowing how to convert its value froma [[Qt:Документация_4.3.2/qvariant  | QVariant]], we can conveniently access fields in a uniform wayacross the wizard. The field mechanism also encourages usto keep the details of creating input widgets local to the respectivewizard pages.
+
Обращаясь к имени поля и зная как преобразовать его значение из [[Qt:Документация_4.3.2/qvariant  | QVariant]], мы можем без труда получать доступ к полям в одинаковой форме через мастр. Механизм полей также позволяет нам хранить подробности создания виджетов ввода локально на соответствующих страницах мастера.
-
Here is how the booking wizard is converted to represent its inputwidgets as fields:
+
Вот как масетер заказов (booking) преобразован, чтобы представить его виджеты ввода как поля:
<source lang="cpp-qt">
<source lang="cpp-qt">
class BookingWizard : public QWizard
class BookingWizard : public QWizard
Строка 129: Строка 127:
...
...
</source>  
</source>  
-
In order for the '''Sailing''' page to have its [[Qt:Документация_4.3.2/qcalendarwidget  | QCalendarWidget]]correctly recognized as a field, we call <tt>registerField()</tt> likethis in the <tt>SailingPage</tt> constructor:
+
Для страницы '''Sailing''' (Отплытие), чтобы её [[Qt:Документация_4.3.2/qcalendarwidget  | QCalendarWidget]] был корректно распознан как поле, мы вызываем <tt>registerField()</tt> в конструкторе <tt>SailingPage</tt>:
<source lang="cpp-qt">
<source lang="cpp-qt">
registerField( "sailing", sailing, "selectedDate",
registerField( "sailing", sailing, "selectedDate",
               SIGNAL(selectionChanged()));
               SIGNAL(selectionChanged()));
</source>  
</source>  
-
For the '''Passenger''' page, we simply call
+
Для страницы '''Passenger''' (Пасажир), мы просто вызываем:
<source lang="cpp-qt">
<source lang="cpp-qt">
registerField("passenger", passenger);
registerField("passenger", passenger);
</source>  
</source>  
-
What about the property and the change signal? These could have beenpassed as the third and fourth arguments to <tt>registerField()</tt>, butby omitting them (effectively passing null pointers instead), we tell[[Qt:Документация_4.3.2/qwizardpage  | QWizardPage]] that we would like to use default values here.[[Qt:Документация_4.3.2/qwizardpage  | QWizardPage]] knows about the most common types of input widgets.Since [[Qt:Документация_4.3.2/qlineedit  | QLineEdit]] is among the lucky ones (a subclass would alsodo), the text property and the <tt>textChanged()</tt> signal isautomatically used.
+
А что со свойством и сигналом изменения? Они могут быть переданы, как третий и четвертый аргументы в <tt>registerField()</tt>, но опуская их (в действительности передавая нулевой указатель), мы говорим [[Qt:Документация_4.3.2/qwizardpage  | QWizardPage]], что мы хотели бы использовать здесь значение по умолчанию. [[Qt:Документация_4.3.2/qwizardpage  | QWizardPage]] знает о наиболее общих типах виджетов ввода. Так как [[Qt:Документация_4.3.2/qlineedit  | QLineEdit]] из числа таких счастливчиков (и подкласс тоже), свойство <tt>text</tt> и сигнал <tt>textChanged()</tt> используются автоматически.
-
Alternatively, we could have added [[Qt:Документация_4.3.2/qcalendarwidget  | QCalendarWidget]] to[[Qt:Документация_4.3.2/qwizard  | QWizard]]'s list of recognized field types once and for all:
+
В качестве альтернативы, мы могли бы добавить [[Qt:Документация_4.3.2/qcalendarwidget  | QCalendarWidget]] в список распознаваемых типов полей [[Qt:Документация_4.3.2/qwizard  | QWizard]]'а, раз и на всегда:
<source lang="cpp-qt">
<source lang="cpp-qt">
setDefaultProperty("QCalendarWidget", "selectedDate", SIGNAL(selectionChanged()));
setDefaultProperty("QCalendarWidget", "selectedDate", SIGNAL(selectionChanged()));
</source>
</source>
-
===Validate Before It's Too Late===
+
===Проверяйте, пока это не слишком поздно===
-
If some information in the wizard is invalid or inconsistent (e.g.,the passenger name is empty), it is currently not detected untilafter the wizard is closed. The wizard would then have to bereopened, and all the information, including the field that was incorrectin the first place, would have to be entered again. This is a verytedious, error-prone, and repetitive process that defeats thepurpose of using a wizard.
+
Если какая-то информация в мастере не верна или недопустима (например, неуказано имя пассажира), она, в данный момент, не обнаруживается до тех пор пока мастер небудет закрыт. Мастер затем должен быть вновь открыт, и вся информация, включая поля, которые были не верны в первый раз, должны быть введены снова. Это очень утомительный, подверженный ошибкам, и повторяющийся процесс, который делает бессмысленной цель использования мастера.
When hitting '''Next''' or '''Finish''' to accept the currentstate of a wizard, the user would intuitively expect the result to beacceptable. We would like errors to be caught and dealt with as earlyas possible.
When hitting '''Next''' or '''Finish''' to accept the currentstate of a wizard, the user would intuitively expect the result to beacceptable. We would like errors to be caught and dealt with as earlyas possible.
Строка 177: Строка 175:
===Инициализация страницы===
===Инициализация страницы===
-
We would now like to ensure that the contents of a page isfilled with sensible values every time the page is entered. Let'sassume that an additional, slightly more expensive cabin type isavailable on Saturdays. By reimplementing the virtual function[http://www.crossplatform.ru/documentation/qtdoc4.3/qwizardpage.php#initializePage QWizardPage::initializePage()], we can populate the [[Qt:Документация_4.3.2/qcombobox  | QComboBox]]representing the cabin types whenever we enter the '''Cabin''' page(assuming the <tt>cabin</tt> combobox is a private member of<tt>SailingPage</tt>):
+
We would now like to ensure that the contents of a page isfilled with sensible values every time the page is entered. Let'sassume that an additional, slightly more expensive cabin type isavailable on Saturdays. By reimplementing the virtual function[http://www.crossplatform.ru/documentation/qtdoc4.3/qwizardpage.php#initializePage QWizardPage::initializePage()], we can populate the [[Qt:Документация_4.3.2/qcombobox  | QComboBox]]representing the cabin types whenever we enter the '''Cabin''' (Каюта) page(assuming the <tt>cabin</tt> combobox is a private member of<tt>SailingPage</tt>):
<source lang="cpp-qt">
<source lang="cpp-qt">
void CabinPage::initializePage()
void CabinPage::initializePage()
Строка 191: Строка 189:
</source>  
</source>  
Notice how the <tt>CabinPage</tt> accesses a field registered by aprevious page ("sailing") to determine the day of the week.
Notice how the <tt>CabinPage</tt> accesses a field registered by aprevious page ("sailing") to determine the day of the week.
-
 
===Пропуск страницы в середине===
===Пропуск страницы в середине===
-
We are now going to support another peculiarity of the ferry company:Cars are not allowed on Saturdays. If the user has selected Saturdayas the sailing date, the '''Car''' page is skipped altogether.
+
Сейчас мы собираемся поддержать другую особенность паромной компании: по субботам автомобили на паром не допускаются. Если пользователь выбирает субботу для отплытия, страница '''Car''' (Автомобиль) пропускается полностью.
[[Image:qq22-skipcar.png|center]]
[[Image:qq22-skipcar.png|center]]
Строка 231: Строка 228:
</source>  
</source>  
Use <tt>nextId()</tt> with care to avoid cycles and non-existent page IDs.Fortunately, [[Qt:Документация_4.3.2/qwizard  | QWizard]] will warn about these cases at run-time.
Use <tt>nextId()</tt> with care to avoid cycles and non-existent page IDs.Fortunately, [[Qt:Документация_4.3.2/qwizard  | QWizard]] will warn about these cases at run-time.
-
 
===Пропуск последней страницы===
===Пропуск последней страницы===

Текущая версия на 19:18, 10 июля 2009

Image:qt-logo_new.png Image:qq-title-article.png
Qt Quarterly | Выпуск 22 | Документация


by Jo Asplin

После исчезновения в клубах дыма, с выходом Qt4, QWizard сново часть Qt. QWizard и его новый подмастерье - QWizardPage, отработавшие свое краткое время в Qt4 Solutions, и теперь насыщенные возможностями, которые сделают работу програмиста мастеров легче, чем когда либо.

Содержание


QWizard предоставляет каркас для написания мастеров (wizard). Цель мастера - провести пользователя через процесс шаг за шагом. Сравнивая класс QWizard предоставляемый Qt 3 и класс совместимости Q3Wizard из Qt 4, новый мастер предоствляет следующие особенности:

  • Естественный внешний вид и поведение на всех платформах
    QWizard supports four different looks — Classic (Windows 95 and X11), Modern(Windows 98 to XP), Aero (Windows Vista), and Mac (Mac OS X). By default, QWizard automatically chooses the most appropriate style for theuser's platform, but this can be overridden.

center

  • Более мощьный и удобный API
    The new API makes iteasy to enable or disable the Next and Finish buttonsbased on the dialog's contents, and to exchange information betweenpages.
  • Поддержка нелинейных мастеров
    Non-linear wizards allow different traversal pathsbased on the information provided by the user.

In this article, we will focus on the control and data flow aspectsof wizards: What happens when the user navigates between pages, whenis the user allowed to navigate between pages, and how do we accessdata on which to base these decisions?

[править] Пример "Книга заказов парома"

Мы будем использовать мастер заказов паромной переправы, чтобы проилюстрировать различные концепции нового каркаса мастеров. Пять используемых страниц, умышленно сделаны очень простыми: Страница для выбора даты отплытия, страница для ввода имени единственного пассажира, страница для выбора типа каюты, страница для указания госномера автомобиля, в случае если вы хотите перевести ваш автомобиль и, наконец, страница ввода номера кредитной карты.

Следующая диаграмма изображает возможные пути навигации с помощью мастера:

center

Исходная реализация выглядит подобно этой:

class BookingWizard : public QWizard
{
public:
    BookingWizard();
 
    QString sailingDate() const
        { return sailing->selectedDate().toString(); }
    QString passengerName() const
        { return passenger->text(); }
    ...
 
private:
    QCalendarWidget *sailing;
    QLineEdit *passenger;
    ...
};
 
class SailingPage : public QWizardPage
{
public:
    SailingPage(QCalendarWidget *sailing) {
        setTitle(tr("Sailing"));
        setLayout(new QVBoxLayout);
        sailing->setMinimumDate(
                QDate::currentDate().addDays(1));
        layout()->addWidget(sailing);
    }
};
 
...
 
BookingWizard::BookingWizard()
{
    setWindowTitle(tr("Ferry Trip Booking Wizard"));
 
    sailing = new QCalendarWidget;
    addPage(new SailingPage(sailing));
 
    passenger = new QLineEdit;
    addPage(new PassengerPage(passenger));
 
    ...
}

Следующий фрагмент кода показывает как открыть мастер и собрать результаты из него:

BookingWizard wizard;
if (wizard.exec()) {
    qDebug() << "booking accepted";
    qDebug() << "sailing date:" << wizard.sailingDate();
    qDebug() << "passenger:" << wizard.passengerName();
    ...
}

Обратите внимание, как класс BookingWizard должен хранить указатели на виджеты ввода всех страниц для того, чтобы реализовать открытый интерфейс. Кроме того, если страница нуждается в доступе к виджету ввода с другой страницы, то указатель на виджет ввода должен быть передан обоим страницам.

[править] Регистрация и использование полей

Чтобы решить проблему идентификации, указанную выше, мы можем использовать механизм полей QWizard'а. Поле состоит из из экземпляра объекта, одного из свойств виджета (представляющее значение виджета), сигнала информирующего нас об изменении свойства (обычно имеется только один такой сигнал) и, наконец, имя, которое должно быть уникальным в пределах мастера.

Обращаясь к имени поля и зная как преобразовать его значение из QVariant, мы можем без труда получать доступ к полям в одинаковой форме через мастр. Механизм полей также позволяет нам хранить подробности создания виджетов ввода локально на соответствующих страницах мастера.

Вот как масетер заказов (booking) преобразован, чтобы представить его виджеты ввода как поля:

class BookingWizard : public QWizard
{
public:
    BookingWizard();
 
    QString sailingDate() const
        { return field("sailing").toString(); }
    QString passengerName() const
        { return field("passenger").toString(); }
    ...
};
 
class SailingPage : public QWizardPage
{
public:
    SailingPage()
    {
        QCalendarWidget *sailing = new QCalendarWidget;
        registerField("sailing", sailing, "selectedDate",
                      SIGNAL(selectionChanged()));
        ...
    }
};
 
class PassengerPage : public QWizardPage
{
public:
    PassengerPage()
    {
        QLineEdit *passenger = new QLineEdit;
        registerField("passenger", passenger);
        ...
    }
};
 
...

Для страницы Sailing (Отплытие), чтобы её QCalendarWidget был корректно распознан как поле, мы вызываем registerField() в конструкторе SailingPage:

registerField( "sailing", sailing, "selectedDate",
               SIGNAL(selectionChanged()));

Для страницы Passenger (Пасажир), мы просто вызываем:

registerField("passenger", passenger);

А что со свойством и сигналом изменения? Они могут быть переданы, как третий и четвертый аргументы в registerField(), но опуская их (в действительности передавая нулевой указатель), мы говорим QWizardPage, что мы хотели бы использовать здесь значение по умолчанию. QWizardPage знает о наиболее общих типах виджетов ввода. Так как QLineEdit из числа таких счастливчиков (и подкласс тоже), свойство text и сигнал textChanged() используются автоматически.

В качестве альтернативы, мы могли бы добавить QCalendarWidget в список распознаваемых типов полей QWizard'а, раз и на всегда:

setDefaultProperty("QCalendarWidget", "selectedDate", SIGNAL(selectionChanged()));

[править] Проверяйте, пока это не слишком поздно

Если какая-то информация в мастере не верна или недопустима (например, неуказано имя пассажира), она, в данный момент, не обнаруживается до тех пор пока мастер небудет закрыт. Мастер затем должен быть вновь открыт, и вся информация, включая поля, которые были не верны в первый раз, должны быть введены снова. Это очень утомительный, подверженный ошибкам, и повторяющийся процесс, который делает бессмысленной цель использования мастера.

When hitting Next or Finish to accept the currentstate of a wizard, the user would intuitively expect the result to beacceptable. We would like errors to be caught and dealt with as earlyas possible.

Let's see how we can improve our booking wizard. How can we ensurethat the passenger name is not empty before proceeding to theCabin page? It turns out that we get the validation we'reafter almost for free when we represent the passenger name as afield. All it takes is to register the field as a mandatory field byappending an asterisk to the name:

registerField("passenger*", passenger);

When we query its value, the field is still referred to using itsregular name (without the asterisk), but being a mandatory field, itis required to be filled (i.e., have a value different from the one ithad at the time of registration) before the Next button isenabled. The default value of a QLineEdit is an empty string, sowe are not allowed to proceed to the Cabin page until weenter a non-empty passenger name.

But how does the wizard know when to check a mandatory field forupdates? Simple: QWizard automatically connects to the changenotification signal associated with the field; e.g.,textChanged() for QLineEdit. This ensures that theNext or Finish button is in the correct "enabled"state at all times.

What if a simple update check is not sufficient to validate a page?Assume for example that there are no departures on Sundays. How can weensure that it is impossible to proceed to the Passenger page aslong as a Sunday is selected as sailing date? A mandatory field would notwork in this case, because there are many invalidvalues (i.e., all Sundays), and there is no way we could have all ofthese represent the invalid initial value to compare the fieldagainst.

We essentially need a way to program the validation ruleourselves. This is achieved by reimplementing the virtual function,QWizardPage::isComplete():

bool SailingPage::isComplete() const
{
    return field("sailing").toDate().dayOfWeek()
           != Qt::Sunday;
}

We also need to emit the QWizardPage::completeChanged() signalevery time isComplete() may potentially return a different value,so that the wizard knows that it must refresh the Next button.This requires us to add the following connect() call to theSailingPage constructor:

connect(sailing, SIGNAL(selectionChanged()),
        this, SIGNAL(completeChanged()));

[править] Инициализация страницы

We would now like to ensure that the contents of a page isfilled with sensible values every time the page is entered. Let'sassume that an additional, slightly more expensive cabin type isavailable on Saturdays. By reimplementing the virtual functionQWizardPage::initializePage(), we can populate the QComboBoxrepresenting the cabin types whenever we enter the Cabin (Каюта) page(assuming the cabin combobox is a private member ofSailingPage):

void CabinPage::initializePage()
{
    cabin->clear();
    cabin->addItem(tr("Cabin without window"));
    cabin->addItem(tr("Cabin with window"));
    if (field("sailing").toDate().dayOfWeek()
            == Qt::Saturday)
        cabin->addItem(tr("Luxury cabin with window and "
                          "champagne"));
}

Notice how the CabinPage accesses a field registered by aprevious page ("sailing") to determine the day of the week.

[править] Пропуск страницы в середине

Сейчас мы собираемся поддержать другую особенность паромной компании: по субботам автомобили на паром не допускаются. Если пользователь выбирает субботу для отплытия, страница Car (Автомобиль) пропускается полностью.

center

By default, the wizard pages are presented in a strictly linearorder: For any given page, there is only one possible page thatcan be arrived from, and only one possible page to proceed to.For instance, the Payment page of our ferry example canonly be arrived at from the Car page, and the Carpage is the only page we can proceed to from the Cabin page.

We will now relax this restriction so that pushing the Nextbutton on the Cabin page takes us to either the Car pageor straight to the Payment page depending on the selectedsailing date. As a consequence, the Payment page may be reacheddirectly from either the Cabin page or the Car page.

The non-linear behavior is achieved by reimplementing thevirtual function, QWizardPage::nextId(). This function is evaluated bythe wizard when the Next button is pressed to determine which page toenter. In order for this to work, we need to associate a unique IDwith each page. The way a unique ID is assigned to a page depends onhow the page is registered in the wizard: addPage() assigns an IDthat is greater than any other ID so far, while setPage() accepts theID as an argument.

The base implementation of nextId() simply returns the next ID inthe increasing sequence of registered IDs. ReimplementingnextId() works best in combination with setPage() asillustrated by the following example:

class BookingWizard : public QWizard
{
public:
    enum { Sailing, Passenger, Cabin, Car, Payment };
    ...
};
int CabinPage::nextId() const
{
    if (field("sailing").toDate().dayOfWeek()
            == Qt::Saturday) {
        return BookingWizard::Payment;
    } else {
        return BookingWizard::Car;
    }
}
BookingWizard::BookingWizard()
{
    ...
    setPage(Car, new CarPage);
    setPage(Payment, new PaymentPage);
    ...
}

Use nextId() with care to avoid cycles and non-existent page IDs.Fortunately, QWizard will warn about these cases at run-time.

[править] Пропуск последней страницы

To illustrate a slightly different use of nextId(), let's drop therule about Saturdays from the previous section and assume instead thatpassengers whose name contains "wizard" don't have to pay for the tripat all — for them, the Car page should be the final page.

center

We achieve this by letting nextId() return {-}1 if thePayment page should be skipped. As it happens, nextId()is not only evaluated when the Next button is pressed to determine whichpage is the next page, but also upon entering a new page to find outwhether there is a next page at all. If there is no next page, theFinish button should replace the Next button. Here isthe code:

int CarPage::nextId() const
{
    if (field("passenger").toString()
           .contains(tr("wizard"), Qt::CaseInsensitive)) {
        return -1;
    } else {
        return BookingWizard::Payment;
    }
}

This of course assumes that the passenger field doesn't change as longas we're on the Car page.


[править] Резюме

The bare bones example we have shown demonstrates how easily wizardnavigation can be programmed using the new QWizard and QWizardPage classes. Most importantly, we have seen howreimplementing virtual functions lets us answer some commonquestions about wizard navigation: When is the user allowed to moveto the next page, which page is to be considered the next one, andon which page can the user accept the current input and close thewizard?In addition to providing easy access to data across the wizard, thefield mechanism we have used offers a basic but extremely convenienttype of page validation through mandatory fields.