Class Wizard Example▲
Most wizards have a linear structure, with page 1 followed by page 2 and so on until the last page. Some wizards are more complex in that they allow different traversal paths based on the information provided by the user. The License Wizard example shows how to create such wizards.
The Class Wizard example consists of the following classes:
-
ClassWizard inherits QWizard and provides a three-step wizard that generates the skeleton of a C++ class based on the user's input.
-
IntroPage, ClassInfoPage, CodeStylePage, OutputFilesPage, and ConclusionPage are QWizardPage subclasses that implement the wizard pages.
ClassWizard Class Definition▲
We will see how to subclass QWizard to implement our own wizard. The concrete wizard class is called ClassWizard and provides five pages:
-
The first page is an introduction page, telling the user what the wizard is going to do.
-
The second page asks for a class name and a base class, and allows the user to specify whether the class should have a Q_OBJECT macro and what constructors it should provide.
-
The third page allows the user to set some options related to the code style, such as the macro used to protect the header file from multiple inclusion (e.g., MYDIALOG_H).
-
The fourth page allows the user to specify the names of the output files.
-
The fifth page is a conclusion page.
Although the program is just an example, if you press Finish (Done on macOS), actual C++ source files will actually be generated.
The ClassWizard Class▲
Here's the ClassWizard definition:
class
ClassWizard : public
QWizard
{
Q_OBJECT
public
:
ClassWizard(QWidget *
parent =
0
);
void
accept() override
;
}
;
The class reimplements QDialog's accept() slot. This slot is called when the user clicks Finish.
Here's the constructor:
ClassWizard::
ClassWizard(QWidget *
parent)
:
QWizard(parent)
{
addPage(new
IntroPage);
addPage(new
ClassInfoPage);
addPage(new
CodeStylePage);
addPage(new
OutputFilesPage);
addPage(new
ConclusionPage);
setPixmap(QWizard::
BannerPixmap, QPixmap(":/images/banner.png"
));
setPixmap(QWizard::
BackgroundPixmap, QPixmap(":/images/background.png"
));
setWindowTitle(tr("Class Wizard"
));
}
We instantiate the five pages and insert them into the wizard using QWizard::addPage(). The order in which they are inserted is also the order in which they will be shown later on.
We call QWizard::setPixmap() to set the banner and the background pixmaps for all pages. The banner is used as a background for the page header when the wizard's style is ModernStyle; the background is used as the dialog's background in MacStyle. (See Elements of a Wizard Page for more information.)
void
ClassWizard::
accept()
{
QByteArray className =
field("className"
).toByteArray();
QByteArray baseClass =
field("baseClass"
).toByteArray();
QByteArray macroName =
field("macroName"
).toByteArray();
QByteArray baseInclude =
field("baseInclude"
).toByteArray();
QString outputDir =
field("outputDir"
).toString();
QString header =
field("header"
).toString();
QString implementation =
field("implementation"
).toString();
...
QDialog::
accept();
}
If the user clicks Finish, we extract the information from the various pages using QWizard::field() and generate the files. The code is long and tedious (and has barely anything to do with noble art of designing wizards), so most of it is skipped here. See the actual example in the Qt distribution for the details if you're curious.
The IntroPage Class▲
The pages are defined in classwizard.h and implemented in classwizard.cpp, together with ClassWizard. We will start with the easiest page:
class
IntroPage : public
QWizardPage
{
Q_OBJECT
public
:
IntroPage(QWidget *
parent =
0
);
private
:
QLabel *
label;
}
;
IntroPage::
IntroPage(QWidget *
parent)
:
QWizardPage(parent)
{
setTitle(tr("Introduction"
));
setPixmap(QWizard::
WatermarkPixmap, QPixmap(":/images/watermark1.png"
));
label =
new
QLabel(tr("This wizard will generate a skeleton C++ class "
"definition, including a few functions. You simply "
"need to specify the class name and set a few "
"options to produce a header file and an "
"implementation file for your new C++ class."
));
label-&
gt;setWordWrap(true
);
QVBoxLayout *
layout =
new
QVBoxLayout;
layout-&
gt;addWidget(label);
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.)
Then we create a QLabel and add it to a layout.
The ClassInfoPage Class▲
The second page is defined and implemented as follows:
class
ClassInfoPage : public
QWizardPage
{
Q_OBJECT
public
:
ClassInfoPage(QWidget *
parent =
0
);
private
:
QLabel *
classNameLabel;
QLabel *
baseClassLabel;
QLineEdit *
classNameLineEdit;
QLineEdit *
baseClassLineEdit;
QCheckBox *
qobjectMacroCheckBox;
QGroupBox *
groupBox;
QRadioButton *
qobjectCtorRadioButton;
QRadioButton *
qwidgetCtorRadioButton;
QRadioButton *
defaultCtorRadioButton;
QCheckBox *
copyCtorCheckBox;
}
;
ClassInfoPage::
ClassInfoPage(QWidget *
parent)
:
QWizardPage(parent)
{
setTitle(tr("Class Information"
));
setSubTitle(tr("Specify basic information about the class for which you "
"want to generate skeleton source code files."
));
setPixmap(QWizard::
LogoPixmap, QPixmap(":/images/logo1.png"
));
classNameLabel =
new
QLabel(tr("&Class name:"
));
classNameLineEdit =
new
QLineEdit;
classNameLabel-&
gt;setBuddy(classNameLineEdit);
baseClassLabel =
new
QLabel(tr("B&ase class:"
));
baseClassLineEdit =
new
QLineEdit;
baseClassLabel-&
gt;setBuddy(baseClassLineEdit);
qobjectMacroCheckBox =
new
QCheckBox(tr("Generate Q_OBJECT &macro"
));
groupBox =
new
QGroupBox(tr("C&onstructor"
));
...
registerField("className*"
, classNameLineEdit);
registerField("baseClass"
, baseClassLineEdit);
registerField("qobjectMacro"
, qobjectMacroCheckBox);
registerField("qobjectCtor"
, qobjectCtorRadioButton);
registerField("qwidgetCtor"
, qwidgetCtorRadioButton);
registerField("defaultCtor"
, defaultCtorR