使用图形编辑框架创建基于 Eclipse 的应用程序
倾向于使用图形的 Eclipse 开发人员如何开始使用 GEF 和其他选项
简介: 了解使用图形编辑框架(Graphical Editing Framework,GEF)创建基于 Eclipse 的应用程序涉及的最初步骤。此外,介绍了目前在 Eclipse 中引导创建图形编辑器过程使用的选项。
本文将介绍使用图形编辑框架(Graphical Editing Framework,GEF)的步骤。我们不是完整地完成每个步骤,而是将使用您的应用程序模型的子集,并先使该子集工作。例如,开始我们可能会忽略连接,或者只注意应用程序中图形元素类型的子集。接下来,了解其他可向应用程序添加图形编辑功能的技术。过去,独立 GEF 曾是在 Eclipse 中进行图形编辑的惟一选择,但是这种情况随着 Eclipse 的发展而发生了改变。
GEF 将假定您具有想用图形显示和编辑的模型。为此,GEF 将提供可以在 Eclipse 工作区的任意位置使用的查看器(EditPartViewer
类型)。类似于 JFace 查看器,GEF 查看器是用于 SWT Control 的适配器。但是相似性仅止于此。GEF 查看器是基于模型-视图-控制器(Model-View-Controller,MVC)架构的。
控制器是连接视图与模型的桥梁(参见图 1)。每个控制器,即本文所谓的 EditPart
,负责将模型映射到视图并对模型进行更改。EditPart
还将监视模型并更新视图以反映模型状态中的更改。EditPart 是与用户进行交互的对象。稍后将详细介绍 EditPart
。
图 1. 模型-视图-控制器

GEF 提供了两种查看器类型:图形查看器和基于树的查看器。每种查看器类型将托管不同类型的视图。图形查看器将使用在 SWT Canvas
上绘制的图形。图形都是在 GEF 附带的 Draw2D 插件中定义的。TreeViewer
将 SWT Tree
和 TreeItem
用于其视图。
GEF 对模型一无所知。任何模型类型应当都能运行,只要它满足下面描述的属性。
一切尽在模型中。模型是惟一被存储和恢复的内容。应用程序应当把所有重要数据存储到模型中。在编辑、撤消和重做的过程中,模型是惟一保持不变的。图形和 EditPart 在经过一段时间后将被回收和重建。
当用户与 EditPart
进行交互时,模型不是由 EditPart
直接处理的。相反,将创建 Command
以封装更改。Command
可用于验证用户的交互,并可用于提供撤消和重做支持。
严格来说,Command
也属于模型的概念范畴。它们本质上不是模型,但是是编辑模型的方法。命令用于执行所有用户的撤消更改。在理想的情况下,命令应当只知道模型。它们应当避免引用 EditPart
或图形。类似地,只要可能,命令应当避免调用用户界面(例如弹出式对话框)。
简单的 GEF 应用程序是用于绘制图形的编辑器。(在这里,图形 仅指图片,而不是类图)。图形可以被模块化为一些形状(shape)。形状可能拥有位置、颜色等属性,并且可能是多个形状构成的一组结构。这里没有什么可惊讶的,并且以前的要求也很易于维护。
图 2. 简单模型

另一个常用 GEF 应用程序是 UML 编辑器,例如类图编辑器。图中的一项重要信息是显示类的 (x, y) 位置。您可能会以为模型必须将一个类描述成具有 x 和 y 特性。大多数开发人员都希望避免用毫无意义的属性来破坏他们的模型。在此类应用程序中,术语业务模型 可用于指代存储重要的语义详细信息 的基本模型。同时,图的特定信息存储在视图模型(即业务模型中的某个视图;可以在一个图中查看多次的对象)中。有时分割甚至还反映在工作区中,各种资源可用于分别保留图和业务模型。同一个业务模型甚至可以有若干个图(参见图 3)。视图模型的常用术语是符号模型。
图 3. 一个模型分割为业务模型和视图模型

不管模型是分割为两部分,还是多个资源,它都不会对 GEF 造成影响。术语模型 指的是整个应用程序模型。屏幕上的对象可以对应模型中的多个对象。GEF 旨在允许开发人员方便地处理这类映射。
对视图的更新几乎应当总是来自模型的通知结果。您的模型必须提供某种通知机制,并且这种机制必须被映射到应用程序的相应更新中。只读模型或不能通知的模型可能是例外,例如文件系统或远程连接。
通知策略通常是分布式的(每个对象)或集中式的(每个域)。域通知程序了解到模型中各个对象的每项更改,并将这些更改广播到域侦听程序中。如果应用程序采用这种通知模型,则将可能为每个查看器添加一个域侦听程序。当侦听程序收到更改时,它将查找受影响的 EditPart
,然后相应地再次发送更改。如果应用程序使用分布式通知,则每个 EditPart
将通常把它自己的侦听程序添加到影响它的模型对象中。
下一步是确定如何使用来自 Draw2D 插件的图形来显示模型。一些图可以直接用于显示模型的对象。例如,Label 图可以用于显示 Image 和 String。有时,需要的结果可以通过组合多个图、布局管理器或边框来实现。最后,您可能要使用特定于应用程序的方法绘制您自己的图形实现。关于组合或实现图和布局的更多信息可以在 GEF SDK 附带的 Draw2D 开发者指南中找到。
在将 Draw2D 与 GEF 结合使用时,通过遵循下列原则,可以使您的项目更便于管理,并且可以更灵活地更改需求:
接下来,我们将用控制器或 EditPart 在模型与视图之间架起桥梁。该步骤在 GEF 中放置 “框架”。提供的类是抽象的,因此客户必须实际编写代码。结果证明,子分类方法不但十分常用,而且还可能是从模型映射到视图最灵活也是最直接的方法。
所提供的用于生成子类的基本实现有三种。将 AbstractTreeEditPart
用于树查看器中显示的 EditPart。在图形查看器中展开 AbstractGraphicalEditPart
和 AbstractConnectionEditPart
。在这里,我们将主要介绍图形 EditPart。相同的原则同样适用于树查看器。
在编写 EditPart 之前,了解 EditPart 的来源,以及当不再需要 EditPart 时怎样处理它们,将很有帮助。每个查看器都配备了一个工厂用以创建 EditPart。在设定查看器的内容时,您可以通过为该查看器提供表示输入的模型对象来完成。通常,输入是最顶部的模型对象,从该对象可以遍历所有其他对象。然后查看器将使用其工厂来为该输入对象构造内容 EditPart。此后,查看器中的每个 EditPart 将填充和管理自己的子 EditPart(和连接),当需要新的 EditPart 时,将委派给 EditPart 工厂,直到填充该查看器。由于新模型对象都是由用户添加的,因此显示那些对象的 EditPart 将通过构造相应的 EditPart 进行响应。注:视图构造与 EditPart 构造同时进行。因此,当每个 EditPart 被构造并被添加到其父 EditPart 中后,同样的过程将发生在视图上,无论是图还是树条目。
只要用户删除相应的模型对象,就丢弃这些 EditPart。如果用户撤销了一个删除操作,那么用于表示被恢复对象而重新创建的 EditPart 与原先的 EditPart 是不同的。这是 EditPart 不能包含长期信息,并且命令不应引用 EditPart 的原因。
编写的第一个 EditPart 是与图本身对应的 EditPart。这个 EditPart 被称为查看器的内容。它对应于模型中最顶部的元素,并且其父元素为查看器的根 EditPart(参见图 4)。根通过提供各种图形层(例如连接层和句柄层等)以及可能会在查看器级别提供的视图缩放或其它功能,为内容打下基础。注:根的函数不依赖于任何模型对象,并且 GEF 为根提供了几个现成的实现。
图 4. 查看器中的 EditPart

内容的图并不太令人感兴趣,并且通常只是包含图的子元素的空面板。它的图形应该为不透明类型(opaque),并且应当利用布局管理器进行初始化,该布局管理器将对图的子图进行布局。但是,它将具有结构。图的直接子元素是由返回的子模型对象列表确定的。清单 1 显示了一个样例内容 EditPart,它创建了一个不透明类型的图形,该图使用 XYLayout
定位其子元素。
清单 1. 内容 EditPart 的初始实现
public class DiagramContentsEditPart extends AbstractGraphicalEditPart { protected IFigure createFigure() { Figure f = new Figure(); f.setOpaque(true); f.setLayoutManager(new XYLayout()); return f; } protected void createEditPolicies() { ... } protected List getModelChildren() { return ((MyModelType)getModel()).getDiagramChildren(); } } |
要确定图中的条目,需要实现 getModelChildren()
。此方法将返回子模型对象(例如图中的节点)列表。超类将使用这个模型对象列表来创建相应的 EditPart。新创建的 EditPart 被添加到部件的子 EditPart 列表。这样又会将每个子 EditPart 的图形添加到示例图。默认情况下,将返回空列表,它表示没有子 EditPart。
其余 EditPart(表示图表中的条目)可能有需要图形化显示的数据。它们还可能有自己的结构,例如连接或自己的子 EditPart。许多 GEF 应用程序利用由标签注明的图标之间的连接来描述这些图标。让我们假定您的 EditPart 将使用 Label 作为它的图形,并且您的模型提供了名称、图标以及与标签之间的连接。清单 2 显示了此类 EditPart 的初始实现。
清单 2. 节点 EditPart 的初始实现
public class MyNodeEditPart extends AbstractGraphicalEditPart { protected IFigure createFigure() { return new Label(); } protected void createEditPolicies() { ... } protected List getModelSourceConnections() { MyModel node = (MyModel)getModel(); return node.getOutgoingConnections(); } protected List getModelTargetConnections() { MyModel node = (MyModel)getModel(); return node.getIncomingConnections(); } protected void refreshVisuals() { MyModel node = (MyModel)getModel(); Label label = (Label)getFigure(); label.setText(node.getName()); label.setIcon(node.getIcon()); Rectangle r = new Rectangle(node.x, node.y, -1, -1); ((GraphicalEditPart) getParent()).setLayoutConstraint(this, label, r); } } |
这里覆盖了一个新方法 refreshVisuals ()
。需要使用来自模型的数据更新图形时,将调用此方法。在这种情况下,模型的名称和图标反映在标签中。但更为重要的是,该标签是通过将其布局约束传递给父元素来定位的。在内容 EditPart 中,我们使用了 XY 布局管理器。该布局使用 Rectangle 约束来确定在何处放置子图形。宽和高的值为 “-1”,表明应当为该图提供理想的大小。
方法 refreshVisuals()
只在 EditPart 的初始化过程中调用一次并且决不再次调用。响应模型通知时,应用程序将负责根据需要再次调用 refreshVisuals()
以更新图。为了提高性能,您可能希望抽取每个模型属性的代码放到它自己的方法中(或者带有 “开关” 的单个方法)。那样,当模型发出通知时,将运行最少量的代码,只刷新发生更改的部分。
另一个有趣的区别是连接支持的代码。类似于 getModelChildren()
,getModelSourceConnections()
和 getModelTargetConnections()
应当返回表示节点之间链接的模型对象。超类将在必要时创建相应的 EditPart 并将其添加到源连接 EditPart 和目标连接 EditPart 的列表。注:连接是被两端的节点引用的,但是连接的 EditPart 只需要创建一次。GEF 将通过首先在查看器中查看连接是否已经存在来确保连接只被创建一次。
编写连接 EditPart
实现没有太大的区别。首先生成 AbstractConnectionEditPart
的子类。跟前面一样,refreshVisuals()
将实现把属性从模型映射到图形中。连接可能还有约束,但是这些约束与以前的约束略有不同。在这里,连接路由器使用了限制来限制连接。而且,连接 EditPart 的图必须为 Draw2D Connection,Draw2D Connection 引入了一个附加要求:连接锚(connection anchor)。
必须通过 ConnectionAnchor
把连接锚定在两端。因而,您必须指明,在连接 EditPart 中或在节点实现中要使用哪些锚。默认情况下,GEF 假定节点 EditPart 将通过实现 NodeEditPart
接口来提供锚。此假定的一个原因是锚的选择依赖于两端节点所使用的图。连接 EditPart 不应当知道节点所使用的图的任何信息。另一个原因是当用户创建连接时,连接 EditPart 不存在,因此节点必须能够自己显示反馈。上承清单 2,我们在清单 3 中添加必要的锚支持。
清单 3. 向节点 EditPart 中添加锚支持
public class MyNodeEditPart extends AbstractGraphicalEditPart implements NodeEditPart { ... public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getSourceConnectionAnchor(Request request) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getTargetConnectionAnchor(Request request) { return new ChopboxAnchor(getFigure()); } ... } |
获得连接的方法是在现有连接 EditPart 上设定锚时所使用的方法。另外两种方法将获得 Request。当用户创建新连接时,将在编辑过程中使用这些方法。对于本示例,所有情况下都将返回 chopbox 锚。chopbox 锚只查找线与节点图形的边框相交的点。实现连接 EditPart 是比较简单的。请注意,甚至无需创建图形,因为默认创建的 PolylineConnection
适用于大多数情况(参见清单 4)。
清单 4. 初始连接 EditPart 实现
public class MyConnectionEditPart extends AbstractConnectionEditPart { protected void createEditPolicies() { ... } protected void refreshVisuals() { PolylineConnection figure = (PolylineConnection)getFigure(); MyConnection connx = (MyConnection)getModel(); figure.setForegroundColor(MagicHelper.getConnectionColor(connx)); figure.setRoutingConstraint(MagicHelper.getConnectionBendpoints(connx)); } } |
创建后,EditPart 应当开始侦听来自模型的更改通知。由于 GEF 是与模型无关的,因此所有应用程序都必须添加自己的侦听程序,并处理得到的通知。收到通知时,处理程序可以调用某个已提供方法来强制进行刷新。例如,如果子模型对象已被删除,则调用 refreshChildren()
将导致对应的 EditPart 及其图也被删除。对于简单的属性更改,可以使用 refreshVisuals()
。正如我们前面提及的,可以将此方法分解成几个部分,从而避免不必要地更新每个显示的属性。
添加侦听程序但却忘记删除它们是造成内存泄漏的常见原因。出于这个原因,应当在 API 中清晰地注明添加和删除侦听程序的点。EditPart 必须继承 activate()
以便添加稍后必须删除的任何侦听程序。通过继承 deactivate()
可以删除那些相同的侦听程序。清单 5 显示了向节点 EditPart 实现添加的模型通知内容。
清单 5. 在节点 EditPart 中侦听模型更改
public class MyNodeEditPart extends AbstractGraphicalEditPart implements NodeEditPart, ModelListener { ... public void activate() { super.activate(); ((MyModel)getModel()).addModelListener(this); } public void deactivate() { ((MyModel)getModel()).removeModelListener(this); super.deactivate(); } public void modelChanged(ModelEvent event) { if (event.getChange().equals("outgoingConnections")) refreshSourceConnections(); else if (event.getChange().equals("incomingConnections")) refreshTargetConnections(); else if (event.getChange().equals("icon") || event.getChange().equals("name")) refreshVisuals(); } ... } |
到目前为止,我们已经介绍了如何创建 EditPart、如何创建 EditPart 的可视图以及当模型发生更改时 EditPart 如何进行更新。除此之外,EditPart 也是对模型进行更改的主要参与者。当命令的请求被发送给 EditPart 时就会发生这种情况。请求还用于要求 EditPart 显示诸如在拖动鼠标时产生的反馈。EditPart 可能支持、阻止给定请求,也可能忽略给定请求。所支持或阻止的请求类型决定了 EditPart 的行为。
侧重点到目前为止都是如何将模型的结构和属性映射到视图中。结果表明,这基本上是在 EditPart 类本身中所做的全部工作。其行为是由一组称为 EditPolicies 的可插入的助手类决定的。在所提供的示例中,我们忽略了方法 createEditPolicies()
。实现此方法后,就几乎已经完成了 EditPart。当然,仍需要提供知道如何修改应用程序模型的编辑策略。由于编辑行为是可插入的,因此在开发各种 EditPart 实现时,可以根据将模型映射到视图和处理模型更新的任务来创建类层次结构。
现在,您已经拥有了以图形方式显示模型所需的全部组成部分。对于最终整合,我们将使用 IEditorPart
。不过,在视图、对话框或者可以放置控件的任意位置也都可以使用 GEF 的查看器。对于此步骤,您必须拥有自己的 UI 插件,它将为正被打开的资源定义编辑器和文件扩展名。可以在同一个插件中定义模型,也可以在独立插件中定义模型。您还需要一个预填充的模型,因为目前还没有编辑功能。
有若干种方法可用于提供样例模型数据。出于本示例的目的,我们将在编辑器被打开时在代码中创建模型,而忽略文件的实际内容。要做到这一点,我们假定已经存在一个测试工厂。或者,您可以创建一个示例向导,该向导将用数据预填充资源(普通向导只创建空图)。最后,您可以用文本编辑器手动编写文档的内容。
现在您有了样例模型,让我们创建将显示模型的编辑器部件。快速开始的方法就是生成子类或复制 GEF 的 GraphicalEditor
。此类将创建 ScrollingGraphicalViewer
的实例,并构造画布用作编辑器的控件。它是十分方便的类,用于帮助您开始使用 GEF;正常工作的 Eclipse 编辑器需要考虑很多其他事情,例如不利的团队环境、正在删除或移动的资源等。
清单 6 显示了一个样例编辑器实现。有几个必须实现的抽象方法。鉴于本文讨论范围的限制,我们将忽略模型持久性和标记。要让图出现在图形查看器中,必须先做两件事:使用您自己的 EditPart 工厂配置查看器,以从 步骤 3 构造 EditPart;然后把图模型对象传递给查看器。
清单 6. 实现编辑器部件
public class MyEditor extends GraphicalEditor { public MyEditor() { setEditDomain(new DefaultEditDomain(this)); } protected void configureGraphicalViewer() { super.configureGraphicalViewer(); //Sets the \ viewer's background to System "white" getGraphicalViewer().setEditPartFactory(new MyGraphicalEditpartFactory()); } protected void initializeGraphicalViewer() { getGraphicalViewer().setContents(MagicHelper.constructSampleDiagram()); } public void doSave(IProgressMonitor monitor) { ... } public void doSaveAs() { ... } public void gotoMarker(IMarker marker) { ... } public boolean isDirty() { ... } public boolean isSaveAsAllowed() { ... } } |
我们已经完成了从仅拥有一个模型到在图形编辑器中显示该模型的全过程。但是这只是奠定了基础。您可以通过阅读 GEF SDK 附带的 “GEF 程序员指南” 获得更多信息。由于本文没有直接附带任何样例,因此我建议 GEF 初学者查看 图形示例,以及 Bo Majewski 撰写的优秀文章 “A Shape Diagram Editor”(请参阅 参考资料)。
随着 GEF 不断成熟,已经有很多构建在 GEF 基础上的健壮框架可以简化在 Eclipse 中开发图形编辑器的过程。必须提及这些框架的原因是,在很多情况下,开发人员都使用这些框架而不是直接在 GEF 本身上构建。
图形模型框架(Graphical Modeling Framework,GMF)
GMF 项目是从手动创建图形编辑器的挫败中产生而来(尤其是在使用 Eclipse Modeling Framework 的环境中)。GMF 将使您可以把语义(商业逻辑)模型高效映射到概念(图形)模型(参见图 5)。使用一些配置文件完成此映射后,GMF 将为您生成一个功能全面的图形编辑器。
图 5. GMF 开发流程

如果用例需要将 Eclipse Modeling Framework 用于模型,则强烈建议使用 GMF 而不是直接使用 GEF。有关更多信息,请阅读 Chris Aniszczyk 的 “Learn Eclipse GMF in 15 minutes”(请参阅 参考资料)。
Zest 是一个轻量级可视化工具包(参见图 6),该工具包将在传统 GEF 编辑器顶部提供类似于 JFace 的包装。Zest 已经在 JFace 之后被模型化,并且所有 Zest 视图都与现有的 Eclipse 视图一样遵守相同的标准和约定(认为包括标签和内容提供程序)。这意味着可以在 Zest 中利用现有应用程序中使用的提供程序、操作和侦听程序。此外,Zest 拥有可重用布局,可以轻松地应用到您的可视化结果中。
图 6. 样例 Zest 可视化

如果用例只需考虑可视化而不需考虑编辑,建议使用 Zest 提供的工具。如果不巧使用了其他可视化工具包,Zest 的布局设计也可以支持其他工具包的重用。
本文的目的在于提供关于 GEF 的优秀介绍,本文的前五部分讨论了 GEF。在那之后,讨论了倾向于图形化的 Eclipse 开发人员在 GEF 领域外部可用的若干个选项。最后,评估用例并查看哪种图形框架能够最好地满足需求非常重要。
<!-- CMA ID: 237383 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
- 访问 Eclipse 图形编辑框架(Graphical Editing Framework,GEF)以了解关于图形编辑框架的更多信息。
- 刚刚接触 GEF 并且需要一个简单而具体的示例?请在 Eclipse.org 查阅 Bo Majewski 撰写的图形示例文章:“A Shape Diagram Editor”。
- 在 Eclipse.org 查阅 GEF 模式编辑器文章 “Building a Database Schema Diagram Editor with GEF”。
- 阅读 GEF 程序员指南 以获得关于 GEF 的(大概)定义性文档。
- 查阅 Eclipse Modeling Framework (EMF) 以获得会对 EMF 初学者有帮助的教程和文档。
- EMF 团队有一篇标题为 “Generating an EMF Model” 的优秀介绍性教程。
- 如果需要关于 EMF 的定义性资源,则 Eclipse Modeling Framework: A Developer's Guide 是本不错的参考书。
- 要获得 GMF 的快速概览,请阅读 “15 分钟学会 Eclipse GMF”。
- Frederic Plante 撰写了一篇标题为 “Introducing the GMF Runtime” 的文章,详细说明了 GMF 运行时的高级功能。
-
Graphical Modeling Framework 维基 提供了关于 GMF 高级功能的教程和大量信息。
- 通过 Richard Gronback 和 Ed Merks 的这个 webinar 了解使用各种 Eclipse 模型框架的信息。
- 在 Eclipse.org 了解 Zest: The Eclipse Visualization Toolkit。
- 要获得关于 Eclipse 平台的介绍性文章,请参阅 “Eclipse 平台入门”。
- 查阅 “Eclipse 推荐读物列表”。
- 查阅 IBM developerWorks 的 Eclipse 项目资源 扩展 PHP 技巧。
- 收听针对软件开发人员的有趣访谈和讨论,一定要访问 developerWorks podcast。
- 随时关注 developerWorks 的 技术事件和网络广播。
- 查阅最近将在全球举办的面向 IBM 开放源码开发人员的研讨会、交易展览、网络广播和其他 活动。
- 访问 developerWorks 开放源码专区,获得丰富的 how-to 信息、工具和项目更新,帮助您用开放源码技术进行开发,并与 IBM 产品结合使用。
获得产品和技术
- 下载 Eclipse 并立即开始使用 Eclipse。
- 在 IBM alphaWorks 中查阅最新的 Eclipse 技术下载。
- 使用 IBM 试用软件 构建您的下一个开发项目,这些软件可以通过下载或从 DVD 中获得。
讨论
- 想要为 GEF 做出贡献?请查阅 GEF 开发邮件列表。
- 查阅 GMF 新闻组 以了解错综复杂的 GMF(选择此链接将启动默认的 Usenet 新闻阅读器应用程序并打开 eclipse.modeling.gmf)。
-
Eclipse Platform 新闻组 应当是讨论关于 Eclipse 的问题的第一站(选择此链接将启动默认的 Usenet 新闻阅读器应用程序并打开 eclipse.platform)。
- 查阅 GEF 新闻组 以获得开发帮助(选择此链接将启动默认的 Usenet 新闻阅读器应用程序并打开 eclipse.tools.gef)。
-
Eclipse 新闻组 中有很多参考资料适用于对使用和扩展 Eclipse 感兴趣的人员。
- 参与 developerWorks blog,加入 developerWorks 社区。

Chris Aniszczyk 是 IBM Lotus 的软件工程师,专门从事 OSGi 相关开发工作。他是开放源码的忠实拥护者,目前在开发 Gentoo Linux 发行版,他还是一些 Eclipse 项目(PDE、ECF、EMFT)的参与者。他十分 乐意与您讨论 关于开放源码和 Eclipse 方面的问题。
相关推荐
BIRT(Business Intelligence and Reporting Tools)是一个基于Eclipse的开源报表系统,主要应用于Java和J2EE的Web应用程序。该系统由两大部分组成:一是Eclipse集成的报表设计工具,二是可嵌入到应用程序中的运行时...
J++,全称Visual J++,是微软在Java 1.1时代推出的一款集成开发环境(IDE),用于开发基于Windows平台的Java应用程序。它是对Microsoft Visual Studio系列产品的扩展,提供了与Visual Basic相似的可视化设计界面,...
内容概要:本文探讨了高吞吐量网络链路异常检测中流量采样技术的应用及其效果。面对现代分布式信息系统频繁遭受的网络安全威胁,特别是互联网服务提供商(ISP)面临的威胁,作者提出一种通过减少数据采样频率以降低异常检测计算复杂度的方法。文中介绍了实验环境、系统架构、采用的数据聚合与采样方法以及用于检测异常的人工智能模型(基于自编码器神经网络)。通过对一个真实中型ISP生产环境中实际网络流量数据进行研究,该研究展示了即使在较低采样频率情况下仍能保持较高的异常检测准确性,尤其是针对持续时间较长的DDoS攻击更为显著。此外,论文还验证了所提系统的有效性和应用潜力,为构建高效的网络安全监控机制提供了新思路。 适用人群:对于计算机网络安全、数据分析或机器学习有兴趣的研究人员和从业人员,特别是那些专注于提高异常检测性能和应对高流量数据流的技术人员。 使用场景及目标:适用于希望在不影响业务操作的前提下引入额外层次防护措施的企业级网络管理员;研究者可参考本文中提出的流量预处理方式来探索不同的统计分布和采样间隔设置;企业可以通过部署该类系统快速响应潜在的安全事件并降低成本。
unity ui画线插件
内容概要:本文研究了在基于正交频分多址接入(OFDMA)的中继网络中进行带有比例公平性的下行链路资源分配问题。作者们通过联合优化中继选择、子载波分配和功率分配问题,并采用拉格朗日对偶分解方法求解这一复杂的NP完全问题。实验结果显示所提出的算法相较于启发式算法能显著提高系统吞吐量,并带来更好的用户间公平性。 适合人群:通信工程、无线网络优化、电信行业研发工程师和研究人员。 使用场景及目标:主要应用于提升4G移动通信系统的频谱效率及缓解频率选择衰落的问题,确保多用户之间的传输速率更加公平。同时适用于研究OFDMA技术及其相关领域的学者和技术专家。 其他说明:文中提供了详细的数学模型和模拟结果图表支持理论发现,并讨论了各种假设条件下的性能对比。此外还探讨了连续松弛技巧在解决NP完全问题时的应用价值以及通过调整算法参数来获得近似最优解的方法论意义。
程序系统设计]MATLAB打印纸缺陷检测GUI(不同缺陷类型,GUI界面) [程序系统设计]MATLAB打印纸缺陷检测GUI(不同缺陷类型,GUI界面) [程序系统设计]MATLAB打印纸缺陷检测GUI(不同缺陷类型,GUI界面) [程序系统设计]MATLAB打印纸缺陷检测GUI(不同缺陷类型,GUI界面) [程序系统设计]MATLAB打印纸缺陷检测GUI(不同缺陷类型,GUI界面)
邮件分拣组态王6.55和西门子S7-200plc联机程序2023,带io表,运行效果视频 ,邮件分拣; 组态王6.55; 西门子S7-200plc; 联机程序2023; IO表; 运行效果视频,邮件分拣组态王6.55与S7-200PLC联机程序2023版:带IO表运行效果视频
内容概要:本文提出了一种新的基于跨时间差异(CTD)注意力机制的变化检测方法(称为CTD-Former),用于高效地提取多时相遥感图像中的变化特征。作者重新审视了自注意力机制并深入挖掘多时间相位图像间的关系变化,构建CTD变压器编码器和解码器来增强这些特征。此外,还引入了一致性感知模块(CPB)以保护变化区域的空间结构。实验结果显示,在LEVIR-CD、WHU-CD和CLCD数据集上,该模型相比于当前最优的方法表现出更好的性能。 适合人群:对深度学习、遥感图像处理、尤其是变化检测感兴趣的研究人员和技术专家,特别是熟悉变换器网络架构的从业者。 使用场景及目标:此方法适用于需要从多时相对比遥感影像中识别变化情况的任务,如环境监测、灾害评估、城市规划等领域内的应用开发,能够帮助研究者和决策者更准确地了解地面物体随时间的变化趋势。 其他说明:源代码可在GitHub仓库中获取,这为未来的研究提供了一个重要的参考平台,有助于推动该领域的进一步发展。
该项目是个人实践项目,答辩评审分达到90分,代码都经过调试测试,确保可以运行!,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载,欢迎沟通,互相学习,共同进步!提供答疑!
fajslghjlghg
2008-2020年各省每十万人口高等学校平均在校生数数据 1、时间:2008-2020年 2、来源:国家统计j、统计nj 3、指标:行政区划代码、地区名称、年份、每十万人口高等学校平均在校生数 4、范围:31省
毕业设计&课程设计 基于STM32单片机基于RFID的电动车停车管理系统(软件源码+硬件资料+部署教程+功能说明+演示视频),高分项目,开箱即用 用户 分为老师 及 学生 管理员 管理员 登录 用户管理 电动车管理 车卡rfid 电动车进出记录 挂失申请列表 解冻申请列表 补办列表申请 用户(只能管理自己的车) 注册(注册的时候选身份,选择学生或者老师) 登录 个人信息查看 电动车管理 进出校记录 挂失申请 解冻申请 补办申请
内容概要:本文探讨了一种新的基于深度强化学习的方法来解决旅行商问题与无人机组合优化(Traveling Salesman Problem with Drone, TSP-D),针对当前无人机辅助卡车配送中面临的协同调度难题进行了改进。研究者提出一种混合模型(HM),整合了注意力编码器和长短期记忆网络(LSTM)解码器的优势,从而有效地记录了多个车辆的动作序列并实现了协调路径规划。该方法在各种测试用例上展现了卓越性能,并能显著提高大型问题实例的计算效率,同时在实际应用场景如最后一步送货中有潜在的巨大价值。 适合人群:对物流系统优化和无人机应用有兴趣的专业人士,特别是从事最后一公里交付方案设计和技术实施的研究人员及工程师。 使用场景及目标:本研究所提出的深度学习框架主要适用于城市环境中复杂条件下的车辆和无人驾驶飞行系统的共同优化配置,目的是为了找到最优的货物递送方案,在最短的时间内完成所有的客户服务任务并返回起点。 其他说明:实验结果显示该算法在随机位置数据集和现实情况中的优越性超过了现有传统算法,表明它不仅能在简单理想情况下发挥良好效果,同样可以在更为复杂的条件下表现出稳定的性能。
北京中启航向科技发展有限公司开发的城市生活垃圾处理费智慧征管系统,是一个全方位、一体化的解决方案,旨在协助城市管理部门高效、准确地收取生活垃圾处理费。该系统利用先进的人工智能和数据分析技术,实现垃圾分类、计量和收费的智能化管理,提升城市环境卫生质量,同时优化行政资源,提高征收效率。
水测试试纸行业剖析:欧洲是全球最大的市场,占40%的份额.pdf
《电力电子技术(第5版)》王兆安_第2章_电力电子器件
基于STM32的直流电机加减速正反转控制串口输出控制系统(P 1100009-基于STM32的直流电机加减速正反转控制串口输出控制系统(PCB 原理图 报告 源代码 proteus lcd1602) 功能描述:基于STM32平台 1、实现了电机控制正转、反转的功能 2、实现了电机控制加速、减速的功能 3、实现了串口输出控制信息的功能 4、串口可以模拟WIFI 蓝牙 RS232 等带有串口的功能。 资料包含: 1、源代码工程文件 2、仿真工程文件 3、lunwen报告1W字以上 4、原理图工程文件 5、PCB工程文件 ,核心关键词:STM32、直流电机、加减速、正反转控制、串口输出、控制信息、WIFI、蓝牙、RS232、源代码工程文件、仿真工程文件、原理图工程文件、PCB工程文件。,基于STM32的电机串口控制综合系统(含正反转、加减速及多种串口通信功能)
ZYNQ7010采集AD7768
apollo 泊车轨迹优化代码 hybridastar+iaps平滑优化+obca平滑优化 第一个图是matlab绘制 后面的图是程序用sdl库绘制 ,apollo;泊车轨迹优化;hybridastar;iaps平滑优化;obca平滑优化;Matlab绘制;SDL库绘制,基于Apollo的泊车轨迹优化:HybridA*算法+平滑优化技术的实现与展示