本例展示怎么用QWizard实现线性向导。例子通过向导为我们在指定目录地点生成了c++代码。
大多数的向导都是线性结构的,一页跟着一页,直到最后一页。一些向导也可能更复杂,以致根据用户输入的信息提供不同的漫游路径。之后有一个License Wizard的例子展示了这样的向导。
类向导例子由下面的类组成:
1. Class Wizard,继承自QWizard。
2. IntroPage, ClassInfoPage, CodeStylePage, OutputFilesPage和ConclusionPage都是QWizardPage的子类。QWizard实现向导页。
本例的ClassWizard类只重新实现了accept()槽,当用户点击Finish的时候就会调用这个槽。
QWizard是继承自QDialog的,而每一个向导页面是由QWizardPage(QWidget的一个子类)来执行的,采用addPage()来增加创建的QWizardPage。
QWizardPage可以添加标题,标题会显示在页的最左上方。setTitle()。还可以设置子标题,子标题跟着标题的下面的位置,起到说明的作用。setSubTitle().
可以用setPixmap来为向导提供图片,void QWizard::setPixmap ( WizardPixmap which, const QPixmap & pixmap )
向导有四种风格:ClassicStyle,ModernStyle,MacStyle,AeroStyle。(setWizardStyle设置)
枚举类WizardPixmap有四个值:
QWizard::WatermarkPixmap:ClassicStyle,ModernStyle页面的左侧设置图片
QWizard::LogoPixmap:ClassicStyle,ModernStyle 右侧设置图片
QWizard::BannerPixmap:ModernStyle设置的背景图片
QWizard::BackgroundPixmap:MacStyle设置背景图片
在很多向导中,页的内容会被一些默认的值或者用户设置的值影响,QWizard提供一个叫“field”(叫它域吧)的机制。它允许在向导页上注册一个域(例如一个QLineEdit),并可以在任何其他页中存取它的值。可以通过QWizardPage::registerField()调用域。这个域也可以是托管的(mandatory)域(带星号“*”),托管的域必须填充才能进入到下一个页。例如:registerField("className*", classNameLineEdit);注册好了以后就可以用field(“**”)使用了。例如:QString className = field("className").toString();域的内容是作为QVariant返回的。
向导可以为自己添加按钮等控件用来指导向导页面的翻转移动,以及结束。Next或Finish按钮是否用一个方法是通过用户的输入,另一个方法是重新实现validateCurrentPage()或QWizardPage::validatePage(),通过它去批准是否生效还可以通过它去确认用户的输入是否符合要求。
下面看代码咯~:
int main(int argc, char *argv[]) { Q_INIT_RESOURCE(classwizard); QApplication app(argc, argv); // 添加国际化支持 QString translatorFileName = QLatin1String("qt_"); translatorFileName += QLocale::system().name(); QTranslator *translator = new QTranslator(&app); if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) app.installTranslator(translator); ClassWizard wizard; wizard.show(); return app.exec(); }
//! [0] class ClassWizard : public QWizard { Q_OBJECT public: ClassWizard(QWidget *parent = 0); void accept(); }; //! [0] //! [1] // 介绍页只有一个标签 class IntroPage : public QWizardPage { Q_OBJECT public: IntroPage(QWidget *parent = 0); private: QLabel *label; }; //! [1] //! [2] // 类信息的东西较多 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; }; //! [2] //! [3] // 代码风格页 class CodeStylePage : public QWizardPage { Q_OBJECT public: CodeStylePage(QWidget *parent = 0); protected: void initializePage(); private: QCheckBox *commentCheckBox; QCheckBox *protectCheckBox; QCheckBox *includeBaseCheckBox; QLabel *macroNameLabel; QLabel *baseIncludeLabel; QLineEdit *macroNameLineEdit; QLineEdit *baseIncludeLineEdit; }; //! [3] // 输出文件页,输出地址+头文件+实现文件 // 重写了initializePage()它在QWizard::restart或点击NEXT时被调用 class OutputFilesPage : public QWizardPage { Q_OBJECT public: OutputFilesPage(QWidget *parent = 0); protected: void initializePage(); private: QLabel *outputDirLabel; QLabel *headerLabel; QLabel *implementationLabel; QLineEdit *outputDirLineEdit; QLineEdit *headerLineEdit; QLineEdit *implementationLineEdit; }; // 最后的结论页,也只有个一个标签 class ConclusionPage : public QWizardPage { Q_OBJECT public: ConclusionPage(QWidget *parent = 0); protected: void initializePage(); private: QLabel *label; };
//! [0] //! [1] ClassWizard::ClassWizard(QWidget *parent) : QWizard(parent) { addPage(new IntroPage); // 添加定义的五个页面 addPage(new ClassInfoPage); addPage(new CodeStylePage); addPage(new OutputFilesPage); addPage(new ConclusionPage); //! [0] setWizardStyle(ModernStyle); // 如果你用的是win7或vista默认的风格是AeroStyle setPixmap(QWizard::BannerPixmap, QPixmap(":/images/banner.png")); setPixmap(QWizard::BackgroundPixmap, QPixmap(":/images/background.png")); setWindowTitle(tr("Class Wizard")); //! [2] } //! [1] //! [2] //! [3] // 最后完成时执行该槽,将信息写入生成文件 void ClassWizard::accept() //! [3] //! [4] { 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(); //! [4] QByteArray block; if (field("comment").toBool()) { block += "/*\n"; block += " " + header.toAscii() + "\n"; // 头文件 block += "*/\n"; block += "\n"; } if (field("protect").toBool()) { block += "#ifndef " + macroName + "\n"; block += "#define " + macroName + "\n"; block += "\n"; } if (field("includeBase").toBool()) { block += "#include " + baseInclude + "\n"; // 引用头文件 block += "\n"; } block += "class " + className; // 定义类 if (!baseClass.isEmpty()) block += " : public " + baseClass; block += "\n"; block += "{\n"; /* qmake ignore Q_OBJECT */ if (field("qobjectMacro").toBool()) { block += " Q_OBJECT\n"; block += "\n"; } block += "public:\n"; if (field("qobjectCtor").toBool()) { // 定义各种风格构造函数 block += " " + className + "(QObject *parent = 0);\n"; } else if (field("qwidgetCtor").toBool()) { block += " " + className + "(QWidget *parent = 0);\n"; } else if (field("defaultCtor").toBool()) { block += " " + className + "();\n"; if (field("copyCtor").toBool()) { block += " " + className + "(const " + className + " &other);\n"; block += "\n"; block += " " + className + " &operator=" + "(const " + className + " &other);\n"; } } block += "};\n"; if (field("protect").toBool()) { block += "\n"; block += "#endif\n"; } QFile headerFile(outputDir + "/" + header); if (!headerFile.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(0, QObject::tr("Simple Wizard"), QObject::tr("Cannot write file %1:\n%2") .arg(headerFile.fileName()) .arg(headerFile.errorString())); return; } headerFile.write(block); block.clear(); if (field("comment").toBool()) { // 一些说明 block += "/*\n"; block += " " + implementation.toAscii() + "\n"; block += "*/\n"; block += "\n"; } block += "#include \"" + header.toAscii() + "\"\n"; block += "\n"; if (field("qobjectCtor").toBool()) { // QObject风格的构造器 block += className + "::" + className + "(QObject *parent)\n"; block += " : " + baseClass + "(parent)\n"; block += "{\n"; block += "}\n"; } else if (field("qwidgetCtor").toBool()) { // QWidget风格的构造器 block += className + "::" + className + "(QWidget *parent)\n"; block += " : " + baseClass + "(parent)\n"; block += "{\n"; block += "}\n"; } else if (field("defaultCtor").toBool()) { // 默认构造函数 block += className + "::" + className + "()\n"; block += "{\n"; block += " // missing code\n"; block += "}\n"; if (field("copyCtor").toBool()) { // 复制构造函数 block += "\n"; block += className + "::" + className + "(const " + className + " &other)\n"; block += "{\n"; block += " *this = other;\n"; block += "}\n"; block += "\n"; block += className + " &" + className + "::operator=(const " + className + " &other)\n"; block += "{\n"; if (!baseClass.isEmpty()) block += " " + baseClass + "::operator=(other);\n"; block += " // missing code\n"; block += " return *this;\n"; block += "}\n"; } } // 执行生成文件 QFile implementationFile(outputDir + "/" + implementation); if (!implementationFile.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(0, QObject::tr("Simple Wizard"), QObject::tr("Cannot write file %1:\n%2") .arg(implementationFile.fileName()) .arg(implementationFile.errorString())); return; } implementationFile.write(block); //! [5] QDialog::accept(); //! [5] //! [6] } //! [6] //! [7] 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->setWordWrap(true); // 由于标签比较长,在分开的地方需要设置断开到下一行 QVBoxLayout *layout = new QVBoxLayout; // 布局管理 layout->addWidget(label); setLayout(layout); } //! [7] //! [8] //! [9] ClassInfoPage::ClassInfoPage(QWidget *parent) : QWizardPage(parent) { //! [8] // 标题和子标题 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")); // Logo //! [10] // 设置部件 classNameLabel = new QLabel(tr("&Class name:")); classNameLineEdit = new QLineEdit; classNameLabel->setBuddy(classNameLineEdit); baseClassLabel = new QLabel(tr("B&ase class:")); baseClassLineEdit = new QLineEdit; baseClassLabel->setBuddy(baseClassLineEdit); qobjectMacroCheckBox = new QCheckBox(tr("Generate Q_OBJECT ¯o")); //! [10] groupBox = new QGroupBox(tr("C&onstructor")); //! [9] qobjectCtorRadioButton = new QRadioButton(tr("&QObject-style constructor")); qwidgetCtorRadioButton = new QRadioButton(tr("Q&Widget-style constructor")); defaultCtorRadioButton = new QRadioButton(tr("&Default constructor")); copyCtorCheckBox = new QCheckBox(tr("&Generate copy constructor and " "operator=")); defaultCtorRadioButton->setChecked(true); connect(defaultCtorRadioButton, SIGNAL(toggled(bool)), copyCtorCheckBox, SLOT(setEnabled(bool))); //! [11] //! [12] // 注册域 registerField("className*", classNameLineEdit); registerField("baseClass", baseClassLineEdit); registerField("qobjectMacro", qobjectMacroCheckBox); //! [11] registerField("qobjectCtor", qobjectCtorRadioButton); registerField("qwidgetCtor", qwidgetCtorRadioButton); registerField("defaultCtor", defaultCtorRadioButton); registerField("copyCtor", copyCtorCheckBox); QVBoxLayout *groupBoxLayout = new QVBoxLayout; // 组框内的布局 //! [12] groupBoxLayout->addWidget(qobjectCtorRadioButton); groupBoxLayout->addWidget(qwidgetCtorRadioButton); groupBoxLayout->addWidget(defaultCtorRadioButton); groupBoxLayout->addWidget(copyCtorCheckBox); groupBox->setLayout(groupBoxLayout); QGridLayout *layout = new QGridLayout; // InfoPage的布局 layout->addWidget(classNameLabel, 0, 0); layout->addWidget(classNameLineEdit, 0, 1); layout->addWidget(baseClassLabel, 1, 0); layout->addWidget(baseClassLineEdit, 1, 1); layout->addWidget(qobjectMacroCheckBox, 2, 0, 1, 2); layout->addWidget(groupBox, 3, 0, 1, 2); setLayout(layout); //! [13] } //! [13] //! [14] CodeStylePage::CodeStylePage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Code Style Options")); setSubTitle(tr("Choose the formatting of the generated code.")); setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo2.png")); commentCheckBox = new QCheckBox(tr("&Start generated files with a " //! [14] "comment")); commentCheckBox->setChecked(true); // 初始化为勾上 protectCheckBox = new QCheckBox(tr("&Protect header file against multiple " "inclusions")); protectCheckBox->setChecked(true); // 初始化为勾上 macroNameLabel = new QLabel(tr("&Macro name:")); // label和lineEdit macroNameLineEdit = new QLineEdit; macroNameLabel->setBuddy(macroNameLineEdit); // 跟上一页的基类关联 includeBaseCheckBox = new QCheckBox(tr("&Include base class definition")); baseIncludeLabel = new QLabel(tr("Base class include:")); baseIncludeLineEdit = new QLineEdit; baseIncludeLabel->setBuddy(baseIncludeLineEdit); // protectCheckBox和它下方的macroNameLabel,macroNameLineEdit保持同步 connect(protectCheckBox, SIGNAL(toggled(bool)), macroNameLabel, SLOT(setEnabled(bool))); connect(protectCheckBox, SIGNAL(toggled(bool)), macroNameLineEdit, SLOT(setEnabled(bool))); // includeBaseCheckBox和它右边的baseIncludeLabel,baseIncludeLineEdit保持同步 connect(includeBaseCheckBox, SIGNAL(toggled(bool)), baseIncludeLabel, SLOT(setEnabled(bool))); connect(includeBaseCheckBox, SIGNAL(toggled(bool)), baseIncludeLineEdit, SLOT(setEnabled(bool))); // 注册域 registerField("comment", commentCheckBox); registerField("protect", protectCheckBox); registerField("macroName", macroNameLineEdit); registerField("includeBase", includeBaseCheckBox); registerField("baseInclude", baseIncludeLineEdit); QGridLayout *layout = new QGridLayout; // 布局 layout->setColumnMinimumWidth(0, 20); // 设置第一列的最小宽20像素 layout->addWidget(commentCheckBox, 0, 0, 1, 3); layout->addWidget(protectCheckBox, 1, 0, 1, 3); layout->addWidget(macroNameLabel, 2, 1); layout->addWidget(macroNameLineEdit, 2, 2); layout->addWidget(includeBaseCheckBox, 3, 0, 1, 3); layout->addWidget(baseIncludeLabel, 4, 1); layout->addWidget(baseIncludeLineEdit, 4, 2); //! [15] setLayout(layout); } //! [15] //! [16] // 上一页类信息的基类和宏影响这一页,上一页点NEXT时触发本槽 void CodeStylePage::initializePage() { QString className = field("className").toString(); macroNameLineEdit->setText(className.toUpper() + "_H");// 定义宏 QString baseClass = field("baseClass").toString(); // 上一页中定义了基类就将本页的相关控件设置 includeBaseCheckBox->setChecked(!baseClass.isEmpty()); includeBaseCheckBox->setEnabled(!baseClass.isEmpty()); baseIncludeLabel->setEnabled(!baseClass.isEmpty()); baseIncludeLineEdit->setEnabled(!baseClass.isEmpty()); if (baseClass.isEmpty()) { // baseClass没有设置 baseIncludeLineEdit->clear(); } else if (QRegExp("Q[A-Z].*").exactMatch(baseClass)) { // baseClass设置了为Q*.*,为Qt库中的类 baseIncludeLineEdit->setText("<" + baseClass + ">"); } else { // 其他情况 baseIncludeLineEdit->setText("\"" + baseClass.toLower() + ".h\""); } } //! [16] OutputFilesPage::OutputFilesPage(QWidget *parent) : QWizardPage(parent) { // 标题 子标题 logo setTitle(tr("Output Files")); setSubTitle(tr("Specify where you want the wizard to put the generated " "skeleton code.")); setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo3.png")); // 创建页中的窗体部件 outputDirLabel = new QLabel(tr("&Output directory:")); outputDirLineEdit = new QLineEdit; outputDirLabel->setBuddy(outputDirLineEdit); headerLabel = new QLabel(tr("&Header file name:")); headerLineEdit = new QLineEdit; headerLabel->setBuddy(headerLineEdit); implementationLabel = new QLabel(tr("&Implementation file name:")); implementationLineEdit = new QLineEdit; implementationLabel->setBuddy(implementationLineEdit); // 注册域 registerField("outputDir*", outputDirLineEdit); registerField("header*", headerLineEdit); registerField("implementation*", implementationLineEdit); // 布局 QGridLayout *layout = new QGridLayout; layout->addWidget(outputDirLabel, 0, 0); layout->addWidget(outputDirLineEdit, 0, 1); layout->addWidget(headerLabel, 1, 0); layout->addWidget(headerLineEdit, 1, 1); layout->addWidget(implementationLabel, 2, 0); layout->addWidget(implementationLineEdit, 2, 1); setLayout(layout); } //! [17] void OutputFilesPage::initializePage() { QString className = field("className").toString(); headerLineEdit->setText(className.toLower() + ".h"); // 头文件 implementationLineEdit->setText(className.toLower() + ".cpp"); // 实现文件 // 输出路径初始化为系统temp的路径 // convertSeparators()是解决不同系统中分隔符的问题 outputDirLineEdit->setText(QDir::convertSeparators(QDir::tempPath())); } //! [17] ConclusionPage::ConclusionPage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Conclusion")); setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/watermark2.png")); label = new QLabel; // 创建label label->setWordWrap(true); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(label); setLayout(layout); } void ConclusionPage::initializePage() { QString finishText = wizard()->buttonText(QWizard::FinishButton); finishText.remove('&'); label->setText(tr("Click %1 to generate the class skeleton.") // label的内容 .arg(finishText)); }