Qt Creator 中,新的工程类型将出现在“文件 -> 新建”菜单项中;我们可以通过打开的选择工程类型的对话框来找到所需要的工程:
在本章中,我们将学习如何向上面所示的对话框中添加新的工程类型。
Core::IWizard接口
Qt Creator 提供了Core::IWizard接口,用于实现添加新的工程类型。该接口在 src/plugins/coreplugin/dialogs/iwizard.h 中声明:
class CORE_EXPORT IWizard
: public QObject
{
Q_OBJECT
public:
enum WizardKind {
FileWizard = 0x01,
ClassWizard = 0x02,
ProjectWizard = 0x04
};
Q_DECLARE_FLAGS(WizardKinds, WizardKind)
IWizard(QObject *parent = 0) : QObject(parent) {}
virtual ~IWizard() {}
virtual WizardKind kind() const = 0;
virtual QIcon icon() const = 0;
virtual QString description() const = 0;
virtual QString displayName() const = 0;
virtual QString id() const = 0;
virtual QString category() const = 0;
virtual QString displayCategory() const = 0;
virtual void runWizard(const QString &path, QWidget *parent) = 0;
// Utility to find all registered wizards
static QList allWizards();
// Utility to find all registered wizards of a certain kind
static QList wizardsOfKind(WizardKind kind);
};
可以看出,Qt Creator 支持一下类型的向导:
Core::IWizard就是实现以上向导所必须实现的接口。
简单实现Core::IWizard
下面,我们自己实现IWizard接口,来添加一个新的工程类型“Custom Project”,目的是让我们的新的工程类型能够显示在“新建工程”对话框中。
实现Core::IWizard接口
首先,新建一个类CustomProjectWizard,实现Core::IWizard:
#ifndef CUSTOMPROJECTWIZARD_H
#define CUSTOMPROJECTWIZARD_H
#include <coreplugin/dialogs/iwizard.h>
class QIcon;
class QString;
class QWidget;
class CustomProjectWizard : public Core::IWizard
{
public:
CustomProjectWizard() { }
~CustomProjectWizard() { }
Core::IWizard::WizardKind kind() const;
QIcon icon() const;
QString description() const;
QString displayName() const;
QString id() const;
QString category() const;
QString displayCategory() const;
void runWizard(const QString &path, QWidget *parent);
};
#endif // CUSTOMPROJECTWIZARD_H
下面,我们将讨论每一个函数的实现。
函数kind()用于告诉 Qt Creator,我们实现的IWizard接口是哪种类型的。它的合法值就是前面所说的IWizard::WizardKind枚举。在我们的例子中,我们返回ProjectWizard:
Core::IWizard::WizardKind CustomProjectWizard::kind() const
{
return IWizard::ProjectWizard;
}
函数icon()返回一个图标,这个图标代表该工程,将会出现在新建对话框列表的左侧。在我们的例子中,我们直接返回 Qt Creator 的图标:
QIcon CustomProjectWizard::icon() const
{
return qApp->windowIcon();
}
函数description()、displayName()、category()、displayCategory()和id()用于返回我们提供的新的工程类型的元数据,比如显示的名字、分类等。其中,以 display 开头的几个函数则用于在界面上显示的字符串,因此我们需要将其用tr()函数返回。
QString CustomProjectWizard::description() const
{
return "A custom project";
}
QString CustomProjectWizard::displayName() const
{
return tr("Custom Project");
}
QString CustomProjectWizard::id() const
{
return "CustomProjectID";
}
QString CustomProjectWizard::category() const
{
return "GalaxyWorld";
}
QString CustomProjectWizard::displayCategory() const
{
return tr("GalaxyWorld");
}
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓
当用户选择了“CustomProject”分类的时候,runWizard()函数将被调用。这个函数必须显示一个对话框,或者一个QWizard对象,用于向用户询问创建新的工程、文件或者类所必须的那些信息。在我们的示例中,这个函数仅仅显示一个对话框:
void CustomProjectWizard::runWizard(const QString &path, QWidget *parent)
{
Q_UNUSED(path);
Q_UNUSED(parent);
QMessageBox::information(parent, "Custom Wizard Dialog", "Hi there!");
}
提供插件
至此我们已经完成自定义工程所需要的代码,下面就需要和前面一样,提供一个插件的封装:
bool CustomProjectWizardPlugin::initialize(const QStringList& args, QString *errMsg)
{
Q_UNUSED(args);
Q_UNUSED(errMsg);
addAutoReleasedObject(new CustomProjectWizard);
return true;
}
下面运行测试一下,就可以在新建对话框中发现我们增加的 Custom Project 类型:
附件下载:CustomProjectWizardPlugin 文件
预定义的IWizard实现:Core::BaseFileWizard
Qt Creator 已经提供了一个默认的IWizard接口的实现,也就是Core::BaseFileWizard类。这个类提供了
IWizard接口的所有函数的默认实现,并且增加了自己特有的虚函数。为了利用这个类,我们需要继承它,并且重写其中的一个或多个函数。
Core::GeneratedFile和Core::GeneratedFiles
通常说,一个新的向导(IWizard的实现)能够提供用户多种提示,并且最终生成一个或者多个文件。Core::GeneratedFile类帮助我们对将要生成的文件进行抽象。很快,我们就可以了解到,在Core::BaseFileWizard的子类中,我们可以为每一个自动生成的文件创建Core::GeneratedFile类的实例。Core::GeneratedFile在 coreplugin/basefilewizard.h 中声明:
class CORE_EXPORT GeneratedFile
{
public:
enum Attribute { // Open this file in editor
OpenEditorAttribute = 0x01,
// Open project
OpenProjectAttribute = 0x02,
/* File is generated by external scripts, do not write out,
* see BaseFileWizard::writeFiles() */
CustomGeneratorAttribute = 0x4
};
Q_DECLARE_FLAGS(Attributes, Attribute)
GeneratedFile();
explicit GeneratedFile(const QString &path);
GeneratedFile(const GeneratedFile &);
GeneratedFile &operator=(const GeneratedFile &);
~GeneratedFile();
// Full path of the file should be created, or the suggested file name
QString path() const;
void setPath(const QString &p);
// Contents of the file (UTF8)
QString contents() const;
void setContents(const QString &c);
QByteArray binaryContents() const;
void setBinaryContents(const QByteArray &c);
// Defaults to false (Text file).
bool isBinary() const;
void setBinary(bool b);
// Id of editor to open the file with
QString editorId() const;
void setEditorId(const QString &k);
bool write(QString *errorMessage) const;
Attributes attributes() const;
void setAttributes(Attributes a);
private:
QSharedDataPointer m_d;
};
typedef QList GeneratedFiles;
需要由Core::BaseFileWizard子类生成的文件由Core::GeneratedFile类对象表示。这个类包含了需要生成的文件的三个关键属性:
- 文件名(及绝对路径)
- 用于编辑文件所需要的编辑器类型,合法值为:CppEditor::Constants::CPPEDITOR_KINDGenericProjectManager::Constants::PROJECT_KINDGit::Constants:: GIT_COMMAND_LOG_EDITOR_KINDGit::Constants:: C_GIT_COMMAND_LOG_EDITOR
- 文件内容
假设我们需要生成如下内容的 C++ 文件:
#include <iostream>
int main()
{
cout << "Hello World\n";
return 0;
}
我们按照下述代码使用Core::GeneratedFile:
#include <coreplugin/basefilewizard.h>
#include <cppeditor/cppeditorconstants.h>
Core::GeneratedFile genFile("C:/Path/To/Source.cpp");
genFile.setEditorId(CppEditor::Constants::CPPEDITOR_ID);
genFile.setContents(
"#include <iostream>\n"
"\n"
"int main()\n"
"{\n"
" cout << \"Hello World\n\";\n"
" \n"
" return 0;\n"
"}"
);
genFile.write(NULL);
Item Model 类向导
假设我们希望提供一个新的类向导,来帮助我们自动生成一个数据项模型的文件。这个文件将基于如下几个数据:
- 模型类名称;
- 父类名称(可以是QAbstractItemModel、QAbstractListModel或者QAbstractTableModel中的一个);
- 头文件名;
- 源代码文件名。
下面,我们就来为 Qt Creator 提供这个“数据项模型”类向导。
第一步:设计类向导界面
首先,我们需要使用 Qt Designer 设计一个简单的界面,目的是向用户搜集我们上面提到的所需要的各个数据:
这个界面被命名为 ModelNamePage.ui。
第二步:实现类向导页面
现在,我们将这个 UI 界面导入 Qt 类,从而可以获取到界面数据。首先,我们需要设计一个结构体,来保存所需数据:
struct ModelClassParameters
{
QString className;
QString headerFile;
QString sourceFile;
QString baseClass;
QString path;
};
下一步,我们声明表示向导页的类,用于将前面我们做出的 UI 类加载进来,以便用户能够使用我们设计的界面来输入需要的内容:
#ifndef MODELNAMEPAGE_H
#define MODELNAMEPAGE_H
#include <QWizardPage>
struct ModelClassParameters
{
QString className;
QString headerFile;
QString sourceFile;
QString baseClass;
QString path;
};
namespace Ui {
class ModelNamePage;
}
class ModelNamePage : public QWizardPage
{
Q_OBJECT
public:
explicit ModelNamePage(QWidget *parent = 0);
~ModelNamePage();
void setPath(const QString& path);
ModelClassParameters parameters() const;
private slots:
void onClassNameChange(const QString & name);
private:
Ui::ModelNamePage *ui;
QString path;
};
#endif // MODELNAMEPAGE_H
构造函数和析构函数都是很简单的:
ModelNamePage::ModelNamePage(QWidget *parent) :
QWizardPage(parent),
ui(new Ui::ModelNamePage)
{
ui->setupUi(this);
}
ModelNamePage::~ModelNamePage()
{
delete ui;
}
函数setPath()用于将文件路径存储下来:
void ModelNamePage::setPath(const QString& path)
{
this->path = path;
}
槽函数onClassNameChange()根据用户填写的类名,自动生成对应的头文件和源代码文件的名字:
void ModelNamePage::onClassNameChange(const QString &name)
{
ui->headerEdit->setText(name + ".h");
ui->implEdit->setText(name + ".cpp");
}
最后, 函数parameters()用于返回ModelClassParameters实例,实际就是返回用户填写的数据:
ModelClassParameters ModelNamePage::parameters() const
{
ModelClassParameters params;
params.className = ui->classNameEdit->text();
params.headerFile = ui->headerEdit->text();
params.sourceFile = ui->implEdit->text();
params.baseClass = ui->baseClassBox->currentText();
params.path = path;
return params;
}