License Wizard Example#
The License Wizard example shows how to implement complex wizards in Qt.
Most wizards have a linear structure, with page 1 followed by page 2 and so on until the last page. The Class Wizard example shows how to create such wizards.
Some wizards are more complex in that they allow different traversal paths based on the information provided by the user. The License Wizard example illustrates this. It provides five wizard pages; depending on which options are selected, the user can reach different pages.
The example consists of the following classes:
QWizardand implements a non-linear five-page wizard that leads the user through the process of choosing a license agreement.
QWizardPagesubclasses that implement the wizard pages.
The LicenseWizard Class#
LicenseWizard class derives from
QWizard and provides a five-page wizard that guides the user through the process of registering their copy of a fictitious software product. Here’s the class definition:
The class’s public API is limited to a constructor and an enum. The enum defines the IDs associated with the various pages:
For this example, the IDs are arbitrary. The only constraints are that they must be unique and different from -1. IDs allow us to refer to pages.
def __init__(self, parent): super().__init__(parent)
In the constructor, we create the five pages, insert them into the wizard using
setPage() , and set
Page_Intro to be the first page.
We set the style to
ModernStyle on all platforms except macOS,
We configure the
QWizard to show a Help button, which is connected to our
showHelp() slot. We also set the
LogoPixmap for all pages that have a header (i.e.,
def showHelp(self): def showHelp(self): ... default: message = tr("This help is likely not to be of any help.")
showHelp(), we display help texts that are appropriate for the current page. If the user clicks Help twice for the same page, we say, “Sorry, I already gave what help I could. Maybe you should try asking a human?”
The IntroPage Class#
The pages are defined in
licensewizard.h and implemented in
licensewizard.cpp, together with
Here’s the definition and implementation of
class IntroPage(QWizardPage): Q_OBJECT # public IntroPage(QWidget parent = None) nextId = int() # private topLabel = QLabel() registerRadioButton = QRadioButton() evaluateRadioButton = QRadioButton() def __init__(self, parent): super().__init__(parent) setTitle(tr("Introduction")) setPixmap(QWizard.WatermarkPixmap, QPixmap(":/images/watermark.png")) topLabel = 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 = QRadioButton(tr("Register your copy")) evaluateRadioButton = QRadioButton(tr("Evaluate the product for 30 " "days")) registerRadioButton.setChecked(True) layout = QVBoxLayout() layout.addWidget(topLabel) layout.addWidget(registerRadioButton) layout.addWidget(evaluateRadioButton) setLayout(layout)
A page inherits from
QWizardPage . We set a
title and a
watermark pixmap . By not setting any
subTitle , we ensure that no header is displayed for this page. (On Windows, it is customary for wizards to display a watermark pixmap on the first and last pages, and to have a header on the other pages.)
nextId() function returns the ID for
EvaluatePage if the Evaluate the product for 30 days option is checked; otherwise it returns the ID for
The EvaluatePage Class#
EvaluatePage is slightly more involved:
class EvaluatePage(QWizardPage): Q_OBJECT # public EvaluatePage(QWidget parent = None) nextId = int() # private nameLabel = QLabel() emailLabel = QLabel() nameLineEdit = QLineEdit() emailLineEdit = QLineEdit() def __init__(self, parent): super().__init__(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., email@example.com).")) nameLabel = QLabel(tr("Name:")) nameLineEdit = QLineEdit ... registerField("evaluate.name*", nameLineEdit) registerField("evaluate.email*", emailLineEdit) ...
First, we set the page’s
Then we create the child widgets, create
wizard fields associated with them, and put them into layouts. The fields are created with an asterisk (
*) next to their name. This makes them
mandatory fields , that is, fields that must be filled before the user can press the Next button (Continue on macOS). The fields’ values can be accessed from any other page using
Resetting the page amounts to clearing the two text fields.
def nextId(self): return LicenseWizard.Page_Conclusion
The next page is always the
The ConclusionPage Class#
DetailsPage are very similar to
EvaluatePage. Let’s go directly to the
class ConclusionPage(QWizardPage): Q_OBJECT # public ConclusionPage(QWidget parent = None) def initializePage(): nextId = int() def setVisible(visible): slots: = private() def printButtonClicked(): # private bottomLabel = QLabel() agreeCheckBox = QCheckBox()
This time, we reimplement
setVisible() , in addition to
nextId() . We also declare a private slot:
The default implementation of
nextId() returns the page with the next ID, or -1 if the current page has the highest ID. This behavior would work here, because
Page_Conclusion equals 5 and there is no page with a higher ID, but to avoid relying on such subtle behavior, we reimplement
nextId() to return -1.
def initializePage(self): licenseText = QString() if wizard().hasVisitedPage(LicenseWizard.Page_Evaluate): licenseText = tr("<u>Evaluation License Agreement:</u> " "You can use self software for 30 days and make one " "backup, but you are not allowed to distribute it.") elif wizard().hasVisitedPage(LicenseWizard.Page_Details): licenseText = tr("<u>First-Time License Agreement:</u> " "You can use self 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)
hasVisitedPage() to determine the type of license agreement the user has chosen. If the user filled the
EvaluatePage, the license text refers to an Evaluation License Agreement. If the user filled the
DetailsPage, the license text is a First-Time License Agreement. If the user provided an upgrade key and skipped the
DetailsPage, the license text is an Update License Agreement.
def setVisible(self, visible): QWizardPage.setVisible(visible) if visible: wizard().setButtonText(QWizard.CustomButton1, tr("Print")) wizard().setOption(QWizard.HaveCustomButton1, True) connect(wizard(), QWizard.customButtonClicked, self.printButtonClicked) else: wizard().setOption(QWizard.HaveCustomButton1, False) disconnect(wizard(), QWizard.customButtonClicked, self.printButtonClicked)
We want to display a Print button in the wizard when the
ConclusionPage is up. One way to accomplish this is to reimplement
If the page is shown, we set the
CustomButton1button’s text to Print, we enable the
HaveCustomButton1option, and we connect the
customButtonClicked()signal to our
If the page is hidden, we disable the
HaveCustomButton1option and disconnect the