MITK/BlueBerry 插件机制探秘:从 .exsd 扩展点到锁定视图布局
2026/7/19 22:57:18 网站建设 项目流程

MITK/BlueBerry 插件机制探秘:从 .exsd 扩展点到锁定视图布局

本文基于 MITK 源码(BlueBerry 框架)整理,梳理三个相关联的问题:

  1. .exsd文件是什么、什么时候用?
  2. 一个plugin.xml为什么会同时出现多个<extension>?
  3. MITK 的视图拖动功能能不能关闭?已发布的程序怎么办?

一、.exsd 文件:扩展点的 Schema 定义

MITK 的界面框架 BlueBerry 移植了 Eclipse 的插件/扩展点(Extension Point)机制。.exsdExtension Point Schema Definition的缩写,即扩展点的 Schema 定义文件,用于描述某个扩展点接受什么样的 XML 结构。

什么时候需要写 .exsd?

只有当你要定义一个新的扩展点时才需要。做法是在plugin.xml中用<extension-point>声明扩展点,并用schema属性指向.exsd文件:

<extension-pointid="org.mitk.example.extensionpointdefinition.changetext"name="Change Text of Label"schema="schema/changetext.exsd"/>

MITK 源码中有一个完整的官方示例:Examples/Plugins/org.mitk.example.gui.extensionpointdefinition

.exsd的内容本质上是一段 XML Schema,规定了扩展方在自己的plugin.xml里写<extension point="...">时,可以/必须提供哪些元素和属性。例如changetext.exsd中定义了changetext元素必须带idnameclass三个属性:

<elementname="changetext"><complexType><attributename="id"type="string"use="required"/><attributename="name"type="string"use="required"/><attributename="class"type="string"use="required"/></complexType></element>

BlueBerry 内置的扩展点也都是这么定义的。org.blueberry.ui.qt插件的plugin.xml中声明了十几个扩展点,每个都配有.exsd:

扩展点Schema 文件用途
org.blueberry.ui.viewsviews.exsd注册视图(View)
org.blueberry.ui.editorseditors.exsd注册编辑器(Editor)
org.blueberry.ui.perspectivesperspectives.exsd注册透视图(Perspective)
org.blueberry.ui.preferencePagespreferencePages.exsd注册偏好设置页
org.blueberry.ui.keywordskeywords.exsd注册偏好设置搜索关键词

一个容易误解的点:.exsd 不参与运行时校验

在 MITK/BlueBerry 的 C++ 运行时中,.exsd文件并不会被用来校验plugin.xml。运行时只是通过ExtensionPoint::GetSchemaReference()记录这个路径字符串而已(见berryExtensionPoint.cpp)。它的实际作用是:

  • 文档作用:告诉扩展方该扩展点的 XML 应该怎么写(每个属性的含义、是否必填);
  • 工具支持:用 Eclipse PDE 工具编辑plugin.xml时可获得表单编辑与校验;
  • 格式兼容:保持与 Eclipse 插件体系一致。

结论:如果你只是扩展别人的扩展点(比如注册一个 View),不需要创建 .exsd,只需按照对应 .exsd 描述的格式在自己的 plugin.xml 里写<extension>即可。

二、为什么一个 plugin.xml 里有多个 <extension>?

先澄清概念:<extension-point>定义扩展点,<extension>扩展(向已有扩展点贡献内容)。两者经常被混为一谈。

以 MITK 标准四窗口编辑器插件org.mitk.gui.qt.stdmultiwidgeteditorplugin.xml为例,它同时扩展了三个扩展点:

<plugin><!-- 1. 注册编辑器本身 --><extensionpoint="org.blueberry.ui.editors"><editorid="org.mitk.editors.stdmultiwidget"name="Standard Display"default="true"class="QmitkStdMultiWidgetEditor"/></extension><!-- 2. 注册它的偏好设置页 --><extensionpoint="org.blueberry.ui.preferencePages"><pageid="org.mitk.StdMultiWidgetEditorPreferencePage"name="Standard Multi Widget"class="QmitkStdMultiWidgetEditorPreferencePage"category="org.mitk.EditorsPreferencePage"><keywordreferenceid="org.mitk.StdMultiWidgetEditorPreferencePageKeywords"/></page></extension><!-- 3. 注册偏好设置页的搜索关键词 --><extensionpoint="org.blueberry.ui.keywords"><keywordid="org.mitk.StdMultiWidgetEditorPreferencePageKeywords"label="crosshair gap size background decoration color corner annotation"/></extension></plugin>

三个<extension>是层层配套的关系:

编辑器 (editors) └── 它的设置页 (preferencePages) └── 设置页的搜索关键词 (keywords)
  • editors:告诉工作台存在一个叫 “Standard Display” 的编辑器,由QmitkStdMultiWidgetEditor实现,且是默认编辑器;
  • preferencePages:这个编辑器有可配置项(十字线间隙、背景色、抗锯齿等),所以向 Preferences 对话框贡献一个设置页,通过category挂到 “Editors” 分类下;
  • keywords:偏好设置对话框有搜索框,这里的关键词通过<keywordreference>关联到设置页——用户搜 “crosshair” 就能找到它。

这就是 Eclipse/BlueBerry 插件体系的典型模式:一个插件 = 一组相关功能的集合,每类功能通过对应的扩展点声明式注册。框架启动时读取这些声明,按需懒加载实际的 C++ 类,插件之间无需硬编码依赖。所以"同时出现多个 extension"不是冗余,而是一个完整功能单元的多个组成部分。

三、MITK 的视图拖动功能可以关闭吗?

可以。BlueBerry 提供了两个层级的开关,都在定义 Perspective 的CreateInitialLayout()里设置。

方式一:锁定整个 Perspective(全局禁止拖动)

voidMyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout){layout->AddView("org.mitk.views.datamanager",berry::IPageLayout::LEFT,0.3f,layout->GetEditorArea());// ...其他视图...layout->SetFixed(true);// 布局固定:所有视图不可拖动、不可缩放}

berryIPageLayout.h中对SetFixed的说明是:“In a fixed layout, layout parts cannot be moved or zoomed”。拖动的判断逻辑在berryPartStack.cpp中:

return!perspective->IsFixedLayout();// fixed 时整个 PartStack 都不允许拖拽

如果 Perspective 是纯声明式注册的,也可以直接在plugin.xml中给<perspective>fixed="true"属性(perspectives.exsd里定义了这个属性)。

注意:SetFixed(true)同时会隐藏视图标签上的关闭按钮、禁止缩放,不只是禁用拖动。

方式二:只锁定某个视图(细粒度控制)

如果只想禁止个别视图被拖动,其他视图保持自由,用IViewLayout:

voidMyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout){layout->AddView("org.mitk.views.datamanager",berry::IPageLayout::LEFT,0.3f,layout->GetEditorArea());berry::IViewLayout::Pointer viewLayout=layout->GetViewLayout("org.mitk.views.datamanager");viewLayout->SetMoveable(false);// 该视图不可拖动// viewLayout->SetCloseable(false); // 顺带也可以禁止关闭}

一个坑:布局是持久化的

这些设置只在 Perspective初次创建布局时生效。如果之前运行过程序,工作台会从上次会话恢复布局(fixed 状态也会被持久化)。测试时建议先Window → Reset Perspective,或清除工作台状态缓存(见下一节)。

四、已发布的程序怎么办?

上面的SetFixed()/SetMoveable()都是开发期的 C++ 接口,必须改源码重新编译。对于已经发布(编译好的)的 MITK Workbench:

  1. 没有用户可见的开关。MITK Workbench 的 Preferences 里没有"锁定布局"选项。Eclipse 的 “Lock the toolbars” 相关代码在 BlueBerry 移植时是被注释掉的(berryWorkbenchWindow.cpp),而且那也只是锁工具栏。
  2. plugin.xml 也改不了。MITK 发布版中每个插件的plugin.xml是作为 Qt 资源编译进插件的 DLL/so 里的,不是磁盘上的独立文件,无法事后修改。
  3. 唯一不重编译的"后门":手改工作台状态文件(仅适合临时验证,见下文)。

结论:要给最终用户提供"不能拖乱界面"的产品,正规做法只有一条——在自己的 Perspective 源码里SetFixed(true)(或对个别视图SetMoveable(false))然后重新构建发布。用户拖乱了布局,只能靠 Window → Reset Perspective 恢复。

五、附:BlueBerry 工作台状态文件在哪?

工作台布局保存在workbench.xml(berryWorkbench.cpp中的DEFAULT_WORKBENCH_STATE_FILENAME),位于org.blueberry.ui.qt插件的数据目录下。整个 BlueBerry 存储根目录的确定逻辑在berryInternalPlatform.cpp:

  1. 如果启动时指定了BlueBerry.storage_dir属性(命令行--BlueBerry.storage_dir=<路径>),就用指定目录;
  2. 否则默认为:
QStandardPaths::GenericDataLocation + 组织名 + "/" + 应用名 + "_" + qHash(程序安装路径) + "/"

Windows 上GenericDataLocationC:\Users\<用户名>\AppData\Local,所以官方 MITK Workbench 的状态目录大致是:

C:\Users\<用户名>\AppData\Local\DKFZ\MitkWorkbench_<一串数字哈希>\

Linux 上对应~/.local/share/<组织名>/<应用名>_<哈希>/

几个要点:

  • 路径末尾带一个安装路径的哈希值——同一程序装在不同目录会各有一份独立状态(源码注释:“allows to start the same application from different build or install trees”);
  • 程序启动时日志会打印Framework storage dir: ...,这是最直接的确认方式;
  • 目录里bb-metadata\bb-plugins\<插件目录>\存放各插件数据,workbench.xml在其中org.blueberry.ui.qt对应的子目录下;.BlueBerryPrefs是偏好设置文件;
  • 整个目录删掉等于"恢复出厂布局";启动参数--BlueBerry.clean也会清掉缓存状态。

如果想验证"锁定布局"的效果而不重编译:关闭程序,在workbench.xml<perspective>节点上加fixed="1",下次启动会按锁定布局恢复(恢复逻辑见berryPerspective.cppTAG_FIXED的读取)。但这个文件格式无文档、程序每次正常退出都会重写,只适合临时验证,不要作为产品方案

总结

问题答案
.exsd 何时用仅在定义新扩展点时;扩展已有扩展点不需要
.exsd 运行时校验吗不校验,主要是文档 + Eclipse PDE 工具支持
多个 <extension> 为什么一个插件的多类功能各自注册到对应扩展点,层层配套
禁止视图拖动layout->SetFixed(true)viewLayout->SetMoveable(false),需重编译
已发布程序无开关、plugin.xml 编译在二进制里改不了;只能手改 workbench.xml 临时验证
状态文件位置%LOCALAPPDATA%\<组织>\<应用>_<哈希>\bb-metadata\bb-plugins\...\workbench.xml

本文源码引用基于 MITK 主线(BlueBerry 框架),文中提到的文件路径:Plugins/org.blueberry.ui.qt/Plugins/org.blueberry.core.runtime/Examples/Plugins/org.mitk.example.gui.extensionpointdefinition/

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询