我们在使用 Qt Creator 创建项目时,弹出的 New File or Project 对话框,便是创建项目的向导。我们可以自定义自己的向导,使用自己的项目模板,来生成自己的初始项目。
Qt Creator 支持json、xml两种格式的向导描述文件,但是xml格式官方已不推荐使用,以下只介绍json格式。
向导文件存放于 Qt Creator 安装目录中的 share/qtcreator/templates/wizards
目录下,向导文件包含用于生成目标的模板文件和 wizard.json
向导配置文件。开发者还可以将制作的向导文件放置在 $HOME/.config/QtProject/qtcreator/templates/wizards
中,放在此目录下的向导只对当前用户有效。
向导文件中支持使用变量,形如:%\{<variableName>\}
,在 wizard.json
文件中可以定义 options 区域,用于申明新变量和值。
变量支持JS表达式,形如:%\{JS:<JavaScript expression>\}
,表达式会被计算并将结果转换成字符串。在表达式中也可以使用定义过的变量,形如:value('<variableName>')
,此返回的值可以使字符串、列表、字典或布尔。
另外,除了能使用 wizard.json
中定义的变量以外,Qt Creator 还提供了一些内置的变量。
- WizardDir -
wizard.json
文件的绝对路径 - Features - Qt Creator 中可用的工具包的所有功能列表
- Plugins - 当前 Qt Creator 中运行的所有插件的列表
- Platform - New File or Project 对话框中选择的平台。可能为空
- InitialPath - 在项目视图中的节点上下文菜单触发向导时,选定节点的路径
- ProjectExplorer.Profile.Ids - 选定节点的项目配置的工具包列表
开发向导时,官方推荐在启动 Qt Creator 时添加 -customwizard-verbose
参数,以便输出更多调试信息。
添加向导
Qt Creator 提供了一个快捷键 Factory.Reset,用于在不重启IDE的情况下重新加载向导。默认情况下,该快捷键没有对应实际的按键,在 工具 > 选项... > 环境 > 键盘 中搜索 Factory.Reset,设置自己习惯的按键即可,方便调试。
下面我们通过官方的C++类创建向导,来分析模板文件的内容。
示例位于 Qt Creator 安装目录下 share/qtcreator/templates/wizards/classes/cpp
中。
首先打开 wizard.json
配置文件
{
"version": 1,
"supportedProjectTypes": [ ],
"id": "A.Class",
"category": "O.C++",
"trDescription": "Creates a C++ header and a source file for a new class that you can add to a C++ project.",
"trDisplayName": "C++ Class",
"trDisplayCategory": "C++",
"iconText": "h/cpp",
"enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}",
"options":
[
{ "key": "TargetPath", "value": "%{Path}" },
{ "key": "HdrPath", "value": "%{Path}/%{HdrFileName}" },
{ "key": "SrcPath", "value": "%{Path}/%{SrcFileName}" },
{ "key": "CN", "value": "%{JS: Cpp.className(value('Class'))}" },
{ "key": "Base", "value": "%{JS: value('BaseCB') === '' ? value('BaseEdit') : value('BaseCB')}" },
{ "key": "isQObject", "value": "%{JS: [ 'QObject', 'QWidget', 'QMainWindow', 'QDeclarativeItem', 'QQuickItem'].indexOf(value('Base')) >= 0 }" },
{ "key": "GUARD", "value": "%{JS: Cpp.classToHeaderGuard(value('Class'), Util.suffix(value('HdrFileName')))}" },
{ "key": "SharedDataInit", "value": "%{JS: (value('IncludeQSharedData')) ? 'data(new %{CN}Data)' : '' }" }
],
"pages":
[
{
"trDisplayName": "Define Class",
"trShortTitle": "Details",
"typeId": "Fields",
"data" :
[
{
"name": "Class",
"trDisplayName": "Class name:",
"mandatory": true,
"type": "LineEdit",
"data": { "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*|)" }
},
{
"name": "BaseCB",
"trDisplayName": "Base class:",
"type": "ComboBox",
"data":
{
"items": [ { "trKey": "<Custom>", "value": "" },
"QObject", "QWidget", "QMainWindow", "QDeclarativeItem", "QQuickItem" ]
}
},
{
"name": "BaseEdit",
"type": "LineEdit",
"enabled": "%{JS: value('BaseCB') === ''}",
"mandatory": false,
"data":
{
"trText": "%{BaseCB}",
"trDisabledText": "%{BaseCB}"
}
},
{
"name": "Sp1",
"type": "Spacer",
"data": { "factor": 2 }
},
{
"name": "IncludeQObject",
"trDisplayName": "Include QObject",
"type": "CheckBox",
"data":
{
"checkedValue": "QObject",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QObject'}"
}
},
{
"name": "IncludeQWidget",
"trDisplayName": "Include QWidget",
"type": "CheckBox",
"data":
{
"checkedValue": "QWidget",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QWidget'}"
}
},
{
"name": "IncludeQMainWindow",
"trDisplayName": "Include QMainWindow",
"type": "CheckBox",
"data":
{
"checkedValue": "QMainWindow",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QMainWindow'}"
}
},
{
"name": "IncludeQDeclarativeItem",
"trDisplayName": "Include QDeclarativeItem - Qt Quick 1",
"type": "CheckBox",
"data":
{
"checkedValue": "QDeclarativeItem",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QDeclarativeItem'}"
}
},
{
"name": "IncludeQQuickItem",
"trDisplayName": "Include QQuickItem - Qt Quick 2",
"type": "CheckBox",
"data":
{
"checkedValue": "QQuickItem",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QQuickItem'}"
}
},
{
"name": "IncludeQSharedData",
"trDisplayName": "Include QSharedData",
"type": "CheckBox",
"data":
{
"checkedValue": "QSharedData",
"uncheckedValue": "",
"checked": false
}
},
{
"name": "Sp2",
"type": "Spacer"
},
{
"name": "HdrFileName",
"type": "LineEdit",
"trDisplayName": "Header file:",
"mandatory": true,
"data": { "trText": "%{JS: Cpp.classToFileName(value('Class'), Util.preferredSuffix('text/x-c++hdr'))}" }
},
{
"name": "SrcFileName",
"type": "LineEdit",
"trDisplayName": "Source file:",
"mandatory": true,
"data": { "trText": "%{JS: Cpp.classToFileName(value('Class'), Util.preferredSuffix('text/x-c++src'))}" }
},
{
"name": "Path",
"type": "PathChooser",
"trDisplayName": "Path:",
"mandatory": true,
"data":
{
"kind": "directory",
"basePath": "%{InitialPath}",
"path": "%{InitialPath}"
}
}
]
},
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
],
"generators":
[
{
"typeId": "File",
"data":
[
{
"source": "file.h",
"target": "%{HdrPath}",
"openInEditor": true,
"options": [
{ "key": "Cpp:License:FileName", "value": "%{HdrFileName}" },
{ "key": "Cpp:License:ClassName", "value": "%{CN}" }
]
},
{
"source": "file.cpp",
"target": "%{SrcPath}",
"openInEditor": true,
"options": [
{ "key": "Cpp:License:FileName", "value": "%{SrcFileName}" },
{ "key": "Cpp:License:ClassName", "value": "%{CN}" }
]
}
]
}
]
}
- version - 文件的版本号,不要修改该值
- supportedProjectTypes - 向已存在的项目中添加新的生成内容时,用于筛选是否可用,支持的值:
AutotoolsProjectManager.AutotoolsProject
CMakeProjectManager.CMakeProject
GenericProjectManager.GenericProject
PythonProject, Qbs.QbsProject
Qt4ProjectManager.Qt4Project (qmake project)
QmlProjectManager.QmlProject - id - 唯一标识符,多个向导会按照同一分类下的id排序。可作为变量
%\{id\}
使用 - category - 向导的分类。可作为变量
%\{category\}
使用 - trDescription - 在 New File or Project 对话框中选中对应类型时,在右侧显示的提示信息。可作为变量
%\{trDescription\}
使用 - trDisplayName - New File or Project 对话框中间显示的名称。可作为变量
%\{trDisplayName\}
使用 - trDisplayCategory - New File or Project 对话框左侧显示的分类名称。可作为变量
%\{trDisplayCategory\}
使用 - icon - New File or Project 对话框中间显示的图标,建议使用基于
wizard.json
文件的相对路径,也可以使用绝对路径 - iconText - 与icon相同,但此处指定的是文字,显示的效果为空白文件图标中存在此处指定的文件
- image - 显示在 trDescription 下的图像的路径
- featuresRequired - 指定依赖的Qt Creator功能,如果缺少所需的功能,将被隐藏。使用 enabled 可以表达更丰富的判断逻辑。可作为变量
%\{RequiredFeatures\}
使用 - featuresPreferred - 指定首选的功能。可作为变量
%\{PreferredFeatures\}
使用 - platformIndependent - 如果所有目标平台都支持,则设置为true。默认设置为false
- enabled - 可使用JS表达式判断当前向导是否显示在 New File or Project 对话框中。默认设置为true
- options - 自定义变量,可在配置文件和模板文件中使用。该区域是一个数组,数组中每个对象定义了一个变量,使用 key 定义变量名, value 定义变量值
- pages - 定义向导页面。可以使用标准页面,或者使用有效的 widget 定义新的页面
- typeId - 指定要使用的标准页面。可用值:Fields, File, Form, Kits, Project, VcsConfiguration, VcsCommand, Summary。每个值的具体意义,【页面】部分会详细说明
- trDisplayName - 页面的标题
- trShortTitle - 向导侧栏中使用的标题
- trSubTitle - 页面的副标题
- index - 指定页面的ID,必须是数字。不指定时自动分配
- enabled - 页面是否显示。true显示,false隐藏
- data - 配置向导页面。该区域是一个数组,数组中的每个对象代表了一张页面。当前C++类向导使用了Fields 和 Summary 两张页面,Fields 页面中使用了 CheckBox, ComboBox, LineEdit, PathChooser, Spacer 组件。每个组件如何使用,【组件】部分会详细说明
- generators - 生成项目时,添加到项目中的文件
- typeId - 生成器的类型。目前,只支持 File 和 Scanner
- data - 详细配置。【生成器】部分会详细说明
页面
配置在 wizard.json
文件的 pages 区域中
Field
字段页。使用指定的组件定义页面,组件的说明详见【组件】部分
{
"trDisplayName": "Define Class",
"trShortTitle": "Details",
"typeId": "Fields",
"data" :
[
{
"name": "Class",
"trDisplayName": "Class name:",
"mandatory": true,
"type": "LineEdit",
"data": { "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)+[a-zA-Z_][a-zA-Z_0-9]*|)" }
},
...
]
}
File
文件页。可以省略 data 项或设置 data 为空对象
{
"trDisplayName": "Location",
"trShortTitle": "Location",
"typeId": "File"
}
Form
表单页。可以省略 data 项或设置 data 为空对象
{
"trDisplayName": "Choose a Form Template",
"trShortTitle": "Form Template",
"typeId": "Form"
}
Kits
工具页。data 项如下:
- projectFilePath - 项目文件路径
- requiredFeatures - 字符串或对象的列表,来描述工具包提供的功能。为对象时,对象的属性如下:
- feature - 描述信息
- condition - 返回true或false,用于确定是否要显示描述
- preferredFeatures - 列出的所有功能匹配的工具包
{
"trDisplayName": "Kit Selection",
"trShortTitle": "Kits",
"typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "projectFilePath": "%{ProFileName}" }
}
Project
项目页。不包含 data 项或者 data 项是一个对象,对象仅有一个 trDescription 属性,在生成的页面中显示
{
"trDisplayName": "Project Location",
"trShortTitle": "Location",
"typeId": "Project",
"data": { "trDescription": "A description of the wizard" }
}
Summary
摘要页。不包含 data 项
如果创建的是顶级项目,则设置变量 IsSubproject
为空字符串,否则设置为 yes,并设置 VersionControl
变量为正在使用的版本控制系统的ID
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
VcsCommand
版本控制页。设置版本控制并显示结果。data 项为对象,属性如下:
- vcsId - 版本控制系统的ID
- trRunMessage - 版本控制系统运行时显示的消息
- extraArguments - 定义传递给版本控制检出命令的附加参数的字符串或字符串列表
- repository - 版本控制远程仓库URL
- baseDirectory - 运行检出操作的目录
- checkoutName - 保存检出数据的子目录
- extraJobs - 定义初次检出后要运行的其他命令的对象列表。对象属性如下:
- skipIfEmpty - 排除命令中的空值参数。默认为true
- directory - 命令运行时的工作目录。默认为 baseDirectory 中定义的目录
- command - 运行的命令
- arguments - 传递给命令的参数
- timeOutFactor - 用于长时间运行的命令,设置比默认超时更长的时间
- enabled - 设置是否支持命令
VcsConfiguration
版本控制配置页。提供用户配置版本控制系统。data 项为对象,属性如下:
- vcsId - 版本控制系统的ID。用于配置 VcsCommand 中指定的版本控制系统,与 VcsCommand 中的 vcsId 对应
组件
Field 页面中可使用的组件,包含:
- Check Box
- Combo Box
- Label
- Line Edit
- Path Chooser
- Spacer
- Text Edit
通用的组件的配置如下:
- name - 组件名
- trDisplayName - 在标签中显示的文本(span 不为 true 时)
- type - 组件的类型:CheckBox, ComboBox, Label, LineEdit, PathChooser, Spacer, TextEdit
- trToolTip - 设置鼠标移动到组件上时的提示
- isComplete - 提供JS表达式返回true或false,只有所有字段的 isComplete 为 true 时,下一步 按钮才可用
- trIncompleteMessage - 当 isComplete 为false时显示
- data - 组件的配置,该区域是一个对象,属性如下:
- visible - 设置是否可见。true可见,false隐藏
- enabled - 设置是否可用。true可用,false不可用
- mandatory - 设置为true时,组件的值不为空则 下一步 按钮变为可用。默认为true
- span - 设置是否隐藏标签。默认为false
以下为各个组件和组件特有的配置
CheckBox
多选框
- checkedValue - 当 checkbox 选中时的值
- uncheckedValue - 当 checkbox 未选中时的值
- checked - 使 checkbox 可用时,设置为true时,否则设置false
{
"name": "IncludeQObject",
"trDisplayName": "Include QObject",
"type": "CheckBox",
"data":
{
"checkedValue": "QObject",
"uncheckedValue": "",
"checked": "%{JS: value('BaseCB') === 'QObject' ? 'true' : 'false'}"
}
}
ComboBox
下拉列表
- items - 数组,列表中的可选项。选项可以是字符串或者对象,对象属性如下:
- trKey - 显示给用户开到的项
- value - 选中时的实际值
- index - 设置组件可用时的顺序。默认为0
- disabledIndex - 设置组件不可用时的顺序
{
"name": "BaseCB",
"trDisplayName": "Base class:",
"type": "ComboBox",
"data":
{
"items": [ { "trKey": "<Custom>", "value": "" },
"QObject", "QWidget", "QMainWindow", "QDeclarativeItem", "QQuickItem" ]
}
}
IconList
带有图标的下拉列表
- items - 数组,列表中的可选项。选项可以是字符串或者对象,对象属性如下:
- trKey - 显示给用户开到的项
- value - 选中时的实际值
- icon - 可选项上的图标
- trToolTip - 提示信息
- index - 设置组件可用时的顺序。默认为0
- disabledIndex - 设置组件不可用时的顺序
{
"name": "ChosenBuildSystem",
"trDisplayName": "Choose your build system:",
"type": "IconList",
"data":
{
"items": [
{ "trKey": "Qbs", "value": "qbs", "icon": "qbs_icon.png", "trToolTip": "Building with Qbs." },
{ "trKey": "QMake", "value": "qmake", "icon": "qmake_icon.png", "trToolTip": "Building with QMake." }
]
}
}
Label
标签。直接显示文本
- wordWrap - 是否包裹住文本,使该组件占用的高度与其他组件保持一致
- trText - 显示的文本
{
"name": "LabelQQC_2_0",
"type": "Label",
"span": true,
"visible": "%{JS: value('CS') === 'QQC_2_0'}",
"data":
{
"wordWrap": true,
"trText": "Creates a deployable Qt Quick 2 application using Qt Quick Controls.",
}
}
LineEdit
单行文本编辑框。占用一行,包含了标签和输入框
- trText - 标签处的文本
- trDisabledText - 组件不可用时显示在标签处的文本
- trPlaceholder - 设置提示的文本
- validator - 使用 QRegularExpression 支持的正则表达式校验输入
- fixup - 设置修正输入的变量。例如,可以将输入的首字母大写
- isPassword - 是否是密码输入框
{
"name": "Class",
"trDisplayName": "Class name:",
"mandatory": true,
"type": "LineEdit",
"data": { "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)+[a-zA-Z_][a-zA-Z_0-9]*|)" }
}
{
"name": "BaseEdit",
"type": "LineEdit",
"enabled": "%{JS: value('BaseCB') === '' ? 'true' : 'false'}",
"mandatory": false,
"data":
{
"trText": "%{BaseCB}",
"trDisabledText": "%{BaseCB}"
}
}
PathChooser
路径选择器
- path - 指定选定的路径。组件初始时的值
- basePath - 指定路径选择的根目录
- kind - 定义选择的内容:existingDirectory, directory, file, saveFile, existingCommand, command, any
{
"name": "Path",
"type": "PathChooser",
"trDisplayName": "Path:",
"mandatory": true,
"data":
{
"kind": "existingDirectory",
"basePath": "%{InitialPath}",
"path": "%{InitialPath}"
}
}
Spacer
空行间隔
- factor - 设置间隔距离
{
"name": "Sp1",
"type": "Spacer",
"data":
{
"factor": 2
}
}
TextEdit
多行文件编辑框
- trText - 文本框中的默认文本
- trDisabledText - 文本框不可用时的文本
- richText - 设置是否支持富文本
{
"name": "TextField",
"type": "TextEdit",
"data" :
{
"trText": "This is some text",
"richText": true
}
}
生成器
File
使用定义好的模板文件生成项目文件。提供 data 区域,配置每一个模板文件。
data 是一个对象,属性如下:
- source - 指定相对于
wizard.json
的模板文件路径 - target - 指定生成的文件位置。可使用绝对路径或相对
%{TargetPath}
的路径。通常由向导页面提供 - openInEditor - 设置为true,则在对应的编辑器中打开。默认为false
- openAsProject - 设置为true,则在 Qt Creator 中打开项目文件。默认为false
- isBinary - 将文件视为二进制文件,避免生成时替换文件中的内容。默认为false
- condition - 判断当此处返回true时生成文件。默认为true
Scanner
扫描 %\{TargetPath\}
路径,生成所有此路径中找到的文件。提供 data 区域,配置筛选条件。
data 是一个对象,属性如下:
- binaryPattern - 设置匹配二进制文件名的正则表达式。任何匹配的文件都将标记为二进制文件,将跳过此文件的模板变量替换
- subdirectoryPatterns - 设置匹配子目录的正则表达式列表,类型为数组。任何匹配的目录中的文件都将被扫描。默认为空列表,表示不会扫描子目录