Tool Window、设置页与持久化¶
真实插件往往需要一个可见的工作区、一组配置项,以及跨 IDE 重启保存状态的能力。本章覆盖 Tool Window、Settings UI 和持久化状态。
Tool Window¶
Tool Window 是 IDE 主窗口边缘的子窗口,用来展示插件自己的信息面板,例如运行结果、分析报告、任务列表或交互式工具。
常见方式有两种:
| 方式 | 适合场景 |
|---|---|
| 声明式注册 | 工具窗口按钮长期可见,用户随时打开 |
| 编程式注册 | 某个 Action 执行后临时展示结果 |
声明式注册¶
<extensions defaultExtensionNs="com.intellij">
<toolWindow
id="Example"
anchor="right"
icon="/icons/example.svg"
factoryClass="com.example.ExampleToolWindowFactory"/>
</extensions>
ToolWindowFactory 会在用户第一次打开窗口时创建内容。这样未使用的 Tool Window 不会拖慢启动。
class ExampleToolWindowFactory : ToolWindowFactory {
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val panel = JPanel(BorderLayout())
panel.add(JLabel("Example"), BorderLayout.NORTH)
val content = ContentFactory.getInstance()
.createContent(panel, "Overview", false)
toolWindow.contentManager.addContent(content)
}
}
条件显示¶
如果 Tool Window 只对某类项目有意义,可以在 factory 中判断适用性。条件通常在项目加载时计算一次;如果要运行时动态显示/隐藏,改用编程式注册。
class ExampleToolWindowFactory : ToolWindowFactory {
override suspend fun isApplicableAsync(project: Project): Boolean {
return true
}
}
Tool Window 内容管理¶
Tool Window 可以包含多个 tab,API 中称为 Content:
- 用
toolWindow.contentManager管理 tab。 - 用
Content.setPreferredFocusableComponent()指定默认聚焦组件。 - 有资源需要释放时,用
Content.setDisposer()挂接Disposable。 - 需要关闭 tab 时,注册时要显式允许
canCloseContents。
如果内容依赖索引,Tool Window 在 Dumb Mode 下默认不可用;若完全不访问索引,可以让 factory 实现 DumbAware。
设置页¶
插件设置页通过 applicationConfigurable 或 projectConfigurable 注册:
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable
parentId="tools"
instance="com.example.AppSettingsConfigurable"
id="com.example.AppSettingsConfigurable"
displayName="Example"/>
</extensions>
项目级设置:
<extensions defaultExtensionNs="com.intellij">
<projectConfigurable
parentId="tools"
instance="com.example.ProjectSettingsConfigurable"
id="com.example.ProjectSettingsConfigurable"
displayName="Example"
nonDefaultProject="true"/>
</extensions>
常用父节点:
parentId |
设置分组 |
|---|---|
appearance |
Appearance & Behavior |
editor |
Editor |
build |
Build, Execution, Deployment |
language |
Languages & Frameworks |
tools |
Tools / third-party integrations |
不要把设置页放进 other,那是兜底分组,不适合新插件。
Configurable 生命周期¶
Configurable 负责创建设置 UI、判断是否修改、应用、重置和释放资源:
class AppSettingsConfigurable : SearchableConfigurable {
private var panel: JPanel? = null
override fun getId(): String = "com.example.settings"
override fun getDisplayName(): String = "Example"
override fun createComponent(): JComponent {
panel = JPanel(BorderLayout())
return panel!!
}
override fun isModified(): Boolean = false
override fun apply() {
// save UI values
}
override fun reset() {
// load stored values into UI
}
override fun disposeUIResources() {
panel = null
}
}
构造函数不要创建复杂 Swing UI。平台可能在后台线程实例化配置对象,UI 应放在 createComponent() 中创建。
持久化状态¶
插件配置通常放在服务中,并实现 PersistentStateComponent。
@Service
@State(
name = "ExampleSettings",
storages = [Storage("example-settings.xml")]
)
class ExampleSettings : SerializablePersistentStateComponent<ExampleSettings.State>(State()) {
data class State(
@JvmField val enabled: Boolean = true,
@JvmField val endpoint: String = ""
)
var enabled: Boolean
get() = state.enabled
set(value) {
updateState { it.copy(enabled = value) }
}
}
建议:
- Application 级状态存全局偏好。
- Project 级状态存项目配置。
- 临时、不可漫游的小值可以用
PropertiesComponent。 - 密码、Token 等敏感信息不要放普通 XML,使用平台的敏感数据存储。
- 可同步设置要谨慎,机器相关路径不应漫游。