简介

从 1.5 版本开始,可以通过将插件文件放置在插件文件夹中,向 Sweet Home 3D 添加新功能。这允许 Java 程序员为 Sweet Home 3D 开发和分发新功能,而无需修改当前版本的源文件(这有利于向上兼容性),也无需交付程序的完整版本(这有利于减小交付大小)。
本文档介绍了创建插件所需的工具,然后展示了如何编程一个插件,该插件计算添加到房屋中的可移动家具的最大体积,最后提供了一些附加信息,以帮助您进一步了解。

安装开发工具

如果 Sweet Home 3D 面向的是普通用户,那么开发插件需要特殊的技能,并且在继续之前,您应该知道如何使用 IDEJava 编程。本指南展示了如何使用 Eclipse 构建插件,但您可以使用您选择的 IDE,或者根本不使用 IDE。

下载并安装 Eclipse

首先从 https://www.eclipse.org/ 下载 Eclipse。名为 Eclipse IDE for Java Developers 的版本足以开发插件,但您可以下载任何用于 Java 开发的版本。
下载完成后,安装 Eclipse 非常简单:只需解压缩您将获得的存档文件,打开 eclipse 文件夹,然后根据您的系统,运行名为的文件 eclipse.exe (在 Windows 下), eclipse.app (在 Mac OS X 下)或 eclipse (在 Linux 下)。
首次运行时,Eclipse 将要求您选择一个工作区文件夹,插件项目将存储在该文件夹中。
完成后,从菜单中选择 文件 > 新建 > 项目 以创建一个新项目,在将显示的 新建项目 向导中选择 Java > Java 项目,输入 VolumePlugin 作为项目名称,然后单击 完成 按钮。最后,关闭 欢迎 选项卡以发现您的工作区,如图 1 所示。

图 1. Eclipse 工作区

下载并安装 Sweet Home 3D 库

插件的开发基于 Sweet Home 3D 的一些类,Eclipse 必须知道这些类才能构建您的项目。将 Sweet Home 3D 类添加到 Eclipse 的最简单方法是下载 Sweet Home 3D 的 JAR 可执行版本,该版本可在 https://sourceforge.net/projects/sweethome3d/files/SweetHome3D/SweetHome3D-7.5/SweetHome3D-7.5.jar/download 获得。下载完成后,将文件 SweetHome3D-7.5.jar 拖放到 Eclipse 的 Package Explorer 视图中的 VolumePlugin 项目图标上,然后在 SweetHome3D-7.5.jar 文件的上下文菜单中选择项目 Build Path > Add to Build Path,如图 2 所示。

图 2. 将 SweetHome3D-7.5.jar
添加到构建路径

编程一个插件

现在您已经安装了所需的工具,让我们看看如何为 Sweet Home 3D 编程您的第一个插件。

创建插件类

首先,通过在 Eclipse 中选择 文件 > 新建 > 类 菜单项,创建一个 com.eteks.sweethome3d.plugin.Plugin 的新子类。

图 3. 创建一个新类

新建 Java 类 对话框中,输入 VolumePlugin 作为类名,输入一个包(这里选择的包是 com.eteks.test),然后选择 com.eteks.sweethome3d.plugin.Plugin 作为 VolumePlugin 的超类。完成后,单击 完成。Eclipse 将创建新类的文件,其内容如下:

package com.eteks.test;
import com.eteks.sweethome3d.plugin.Plugin;
import com.eteks.sweethome3d.plugin.PluginAction;
public class VolumePlugin extends Plugin {
@Override
public PluginAction[] getActions() {
// TODO Auto-generated method stub
return null;
}
}

正如您可以从 TODO 注释中猜到的那样,您现在必须更改 getActions 方法的实现,以返回一个能够计算可移动家具体积的插件操作。将 return null; 替换为以下语句:

  return new PluginAction [] {new VolumeAction()};  

然后从 Eclipse 菜单中选择 Edition > Quick Fix 以创建缺少的类 VolumeAction,如图 4 所示。

图 4. 使用快速修复生成缺少的类

在出现的 新建 Java 类 对话框中,选中 Enclosing type 复选框以创建 VolumePlugin 的内部类,然后单击 完成。这将创建从 com.eteks.sweethome3d.plugin.PluginAction 类继承的 VolumeAction 类,并包含一个空的 execute 方法:

  public class VolumeAction extends PluginAction {
@Override
public void execute() {
// TODO Auto-generated method stub
}
}

此方法是 Sweet Home 3D 在用户启动插件操作时将调用的方法;因此,您必须在此处实现如何计算家具的体积并显示它:

  public class VolumeAction extends PluginAction {  
@Override
public void execute() {
float volumeInCm3 = 0;
// Compute the sum of the volume of the bounding box of
// each movable piece of furniture in home
for (PieceOfFurniture piece : getHome(). getFurniture()) {
if (piece. isMovable()) {
volumeInCm3 += piece. getWidth()
* piece. getDepth()
* piece. getHeight();
}
}

// Display the result in a message box (³ is for 3 in supercript)
String message = String. format(
"The maximum volume of the movable furniture in home is %.2f m³.",
volumeInCm3 / 1000000);
JOptionPane. showMessageDialog(null, message);
}
}

现在您已经指定了您希望插件执行的操作,您必须描述用户将如何启动此新操作。您可以选择向菜单添加新的 菜单项,和/或向工具栏添加新的 按钮。此选择是通过在其创建时设置插件操作的适当属性来完成的。例如,如果您希望用户使用 工具 菜单中找到的菜单项 计算体积 启动体积操作,您将向 VolumnAction 类添加以下构造函数:

  public VolumeAction() {
putPropertyValue(Property.NAME, "Compute volume");
putPropertyValue(Property.MENU, "Tools");
// Enables the action by default
setEnabled(true);
}

VolumePlugin 插件类现在已编程完成,并且几乎可以作为 Sweet Home 3D 中的插件工作。最后要做的两件事是:

  • 创建一个 ApplicationPlugin.properties 描述文件,
  • 将文件放在一个 JAR 文件中。

创建插件描述文件

一个 ApplicationPlugin.properties 文件 描述了插件名称、其类、支持它的 Sweet Home 3D 和 Java 最低版本 以及法律内容。从文件 > 新建 > 文件 中选择 Eclipse 菜单,输入文件名 ApplicationPlugin.properties,然后单击 完成,如图所示 在图 5 中。

图 5. 创建一个新文件

然后在新文件中输入以下描述并保存它:

name=可移动家具体积
class=com.eteks.test.VolumePlugin
description=计算房屋中可移动家具的体积
version=1.0
license=GNU GPL
provider=(C) Copyrights 2024 Space Mushrooms
applicationMinimumVersion=1.5
javaMinimumVersion=1.5

创建插件 JAR

插件 JAR 包含从 VolumePlugin.java 文件 的编译创建的 class 文件,以及 ApplicationPlugin.properties 文件。由于 Eclipse 会在您保存 Java 文件后立即对其进行编译,因此您 只需从菜单中选择 文件 > 导出…,然后在将显示的 导出 对话框 中选择 Java > JAR 文件。在出现的 Jar 导出 向导中,如图 6 所示,选中项目复选框 并输入放置在 Sweet Home 3D 插件文件夹中的 JAR 文件的路径。此适当的文件夹取决于 您的系统,如下所示:

  • 在 Windows Vista / 7 / 8 / 10 / 11 下,此文件夹是 C:\Users\user\AppData\Roaming\eTeks\Sweet Home 3D\plugins
  • 在 Windows XP 和以前版本的 Windows 下,此文件夹是 C:\Documents and Settings\user\Application Data\eTeks\Sweet Home 3D\plugins
  • 在 macOS 下,它是您的 用户文件夹的子文件夹 Library/Application Support/eTeks/Sweet Home 3D/plugins
  • 在 Linux 和其他 Unix 下,它是您的用户文件夹的子文件夹 .eteks/sweethome3d/plugins
图 6. 导出到 JAR 文件

测试插件

您开发的 插件 将在 Sweet Home 3D 中运行,无论是使用 Java Web Start 版本、安装程序 版本还是您之前下载的 SweetHome3D-7.5.jar。由于最新版本是一个可执行 JAR,您可以通过双击它或使用以下命令来运行它:

您开发的 插件 将在 Sweet Home 3D 中运行,无论是使用 Java Web Start 版本、安装程序 版本还是您之前下载的 SweetHome3D-7.5.jar。由于最新版本是一个可执行 JAR,您可以通过双击它或使用以下命令来运行它:

java -jar /path/to/SweetHome3D-7.5.jar

只要您正在测试,您可能更喜欢使用此命令运行 Sweet Home 3D,以便能够在控制台中读取插件执行期间抛出的异常的堆栈跟踪。

启动 Sweet Home 3D 后,您将看到新菜单及其项目出现,如图 7 所示:

图 7. 插件菜单

如果您为在 用户指南 中创建的 家庭示例 选择新菜单项,您将获得以下结果:

图 8. 运行中的插件

调试插件

如果您需要从 Eclipse 调试您的插件,请按照以下步骤创建调试配置:

  • 从菜单中选择 Run > Debug Configurations…,在 Debug configurations 对话框的可用配置列表中选择 Java Application 项目,单击左上角的 New 按钮,然后输入配置的名称。
  • 单击 Main class 文本字段右侧的 Search… 按钮,然后双击建议的类中的 SweetHome3DBootstrap
图 9. 创建调试配置
  • 单击 Classpath 选项卡,在 Classpath 列表中的 User Entries 项目的 VolumePlugin (default classpath) 子项目,然后单击 Remove 按钮。
  • 单击 Classpath 列表中的 User Entries 项目,单击 Add JARs… 按钮,选择 SweetHome3D-7.5.jar 项目并确认您的选择。
图 10. 设置调试配置的类路径
  • 选择 Source 选项卡,单击 Add… 按钮,在 Add Source 对话框中双击 Java Project 项目,在 Project Selection 弹出窗口中选择 VolumePlugin 项目,然后确认您的选择。
图 11. 设置调试配置的源路径
  • 最后,单击 Debug 按钮以在调试模式下启动 Sweet Home 3D。程序运行后,打开 VolumePlugin.java 文件, 在 execute 方法中设置一个断点,然后从 Sweet Home 3D 菜单中选择 Tools > Compute volume。Eclipse 将在选定的 断点处停止,让您逐步执行程序并检查变量值。
图 12. Eclipse 调试透视图

每次修改插件的源代码时,请不要忘记在启动您创建的调试配置之前生成插件 JAR。为了加快 eclipse 中的 JAR 导出过程,请转到 JAR 导出向导的第二步,然后选择选项 Save the description of this JAR in the workspace。这将在项目中添加一个新项目,其中包含上下文 Create JAR 菜单项。

部署插件

准备就绪后,只需将其复制到其他 Sweet Home 3D 用户的 插件文件夹 中,即可将您的插件部署到他们的计算机上。从 1.6 版本开始,如果插件文件的扩展名为 SH3P(只需将文件扩展名从 .zip 更改为 .sh3p),也可以通过双击它将其安装到 Sweet Home 3D 的插件文件夹中。如果双击 .sh3p 文件没有启动 Sweet Home 3D(在 Linux 下最有可能),您还可以使用以下命令在 Terminal 窗口中安装插件(其中 SweetHome3D 是 Sweet Home 3D 安装程序提供的可执行文件的名称):

/path/to/SweetHome3D /path/to/plugin.sh3p

要停止使用插件,请从插件文件夹中删除其文件并重新启动 Sweet Home 3D。

如果您希望您的插件能够与此网站上提供的所有 Sweet Home 3D 安装程序 一起运行,请注意使其与 Java 5 兼容,方法是在 Java Compiler 部分的 Compiler compliance level 字段中选择 1.5,该对话框由 Eclipse 的 Project > Properties 菜单项显示。
如果您使用的 Java 编译器版本不再提供 Java 1.5 兼容性,请尝试至少以 Sweet Home 3D 最新版本中仍使用的 Java 1.8 为目标,并在插件的 ApplicationPlugin.properties 文件中相应地设置 javaMinimumVersion

更进一步

第一个插件的编程向您展示了全局情况。以下是一些附加信息,可帮助您进一步了解。

Sweet Home 3D API – Javadoc

开发新插件最有用的文档是使用 javadoc 工具生成的 Sweet Home 3D API(应用程序编程接口)。
如果您希望您的插件与 Sweet Home 3D 的未来版本向上兼容,请仅在您的插件中使用 com.eteks.sweethome3d.plugincom.eteks.sweethome3d.modelcom.eteks.sweethome3d.toolscom.eteks.sweethome3d.viewcontroller 包的类。这足以编程任何处理 Sweet Home 3D 中可用的家庭数据的插件。
Javadoc 中包含与程序其他层匹配的包,仅供参考。不要依赖它们的 API,因为它将来可能会更改,并且不保证向上兼容性(无论如何,您都不会在上述包中看到对 com.eteks.sweethome3d.swingcom.eteks.sweethome3d.j3dcom.eteks.sweethome3d.iocom.eteks.sweethome3d 包的类的引用)。

模型类架构

Sweet Home 3D 基于 MVC(模型视图控制器)架构,因此了解其模型层的组织方式至关重要。图 13(也可在 PDF 格式 中获得)展示了与此模型层匹配的 com.eteks.sweethome3d.model 包的 1.5 版本中几乎所有可用的类和接口。

[uml_diagram slug=”model-classes-diagram” map_name=”model-classes-diagram” caption=”Figure 13. UML diagram of com.eteks.sweethome3d.model package” caption_small=”(click on a class to view its javadoc)”]

模型层中的中心类是 HomeApplication 类 (10),它是 SweetHome3D 应用程序主类的抽象超类。此类的实例允许访问当前编辑的 Home 实例 (7),以及存储正在使用的 长度单位 (12)、家具目录 (14) 和用户从中选择 家具 (17) 和 纹理 (18) 的 纹理目录 (15) 的 UserPreferences 对象 (11)。
Home 实例 (7) 存储用户在家庭计划中创建的所有对象:

这些对象实现了 Selectable 接口 (1) 以及 ObserverCamera 对象 (4),该对象存储相机在 Virtual visitor 模式下的位置。模型对象管理的任何外部信息,例如 家具 (16) 的图标和 3D 模型,或 纹理 (20) 的图像,都可以通过 Content 接口 (19) 访问,该接口由 URLContent 类和 com.eteks.sweethome3d.tools 包的其他类实现。

此 UML 图应帮助您了解 Sweet Home 3D 模型中可用的类以及如何访问它们,但您可能会注意到其中没有引用构造函数和 mutator(或者如果您愿意,可以使用 setter)。这只是因为空间不足,但您可以在插件类中毫无问题地使用它们。另请注意,对模型现有对象的任何修改都将通过 PropertyChangeEventCollectionEvents (8) 或 SelectionEvents (6) 通知给显示的组件,从而允许所有更改立即反映在屏幕上。

出于性能原因,Sweet Home 3D 模型不是线程安全的。对属于模型的对象的修改应在事件分派线程中完成。

插件类架构

插件类的架构比模型层的架构更容易理解。com.eteks.sweethome3d.plugin 包仅包含三个类,其中您应该仅使用 PluginPluginAction 类,如图 14 所示(也可在 PDF 格式 中获得)。

[uml_diagram slug=”plugin-classes-diagram” map_name=”plugin-classes-diagram” caption=”Figure 14. UML diagram of com.eteks.sweethome3d.plugin package” caption_small=”(click on a class to view its javadoc)”]

在应用程序启动时创建一个 PluginManager 实例 (1),并搜索安装在用户 插件文件夹 中的插件。每次编辑新家庭时,此管理器都会为启动时找到的每个插件实例化和配置一个 Plugin 对象 (3)。然后,它调用 getActions 方法来检索所有将作为菜单项和/或工具栏按钮添加到家庭窗口中的 操作 (4)。每个操作都是 PluginAction 的一个实例,它看起来像 Action 类,具有其 execute 方法及其可修改的 属性 (2)。

请注意,Plugin 类允许您通过其 getUndoableEditSupport 方法访问 UndoableEditSupport 实例。只要您在 PluginAction 实例的 execute 方法中修改家庭或其对象(家具、墙壁…),您还应该将 UndoableEdit 对象发布到 getUndoableEditSupport 方法返回的可撤消编辑支持,否则用户将无法正确撤消/重做您所做的更改。

本地化

如果您计划为 Sweet Home 3D 用户社区开发插件,请尝试本地化它在操作名称和菜单或您将创建的对话框中显示的字符串(或者至少准备好它的本地化)。PluginAction 的两个构造函数 将帮助您使用 .properties 文件组织操作属性的翻译,如果您需要在插件中翻译其他字符串(例如 测试插件 显示的对话框中的字符串),请使用 ResourceBundle Java 类重用这些 .properties 文件。
如果您希望限制属性文件的数量,您甚至可以将操作属性和其他字符串的值写入插件的 ApplicationPlugin.properties 描述文件 中。

如果您想要一个使用此架构的示例,请下载 Export to SH3F 插件,该插件可在 https://test.sweethome3d.eu/plugins/ExportToSH3F-1.0.sh3p 获得,并解压缩它(此插件文件还包含插件的源代码)。
Help forum 中所述,此插件创建一个 SH3F 文件,其中包含您导入到 Sweet Home 3D 家具目录中的所有家具。

贡献插件

您可以将您编程的插件发布到 Plug-ins Contributions 跟踪系统中,以便与 Sweet Home 3D 用户社区共享它们。
借助插件,可以向 Sweet Home 3D 添加许多功能,从导入器到导出器,还可以添加能够修改家庭数据的插件,例如 Michel Mbem 开发的 Home Rotator Plug-in 以及 Hans Dirkse 编写的 Tutorial for Plug-ins and Extensions (PDF) 和 Plug-ins and tools 页面中列出的其他插件。