5. 客户端GUI开发

5.1. 介绍

在uk.ac.gda.example.Feature插件中可以找到一个示例RCP客户端产品。这包含两个视角:

  • 脚本

  • 实验

脚本提供了查看、编辑和运行Jython脚本的工具。它有显示GDA的Jython环境的Jython控制台视图。Jython引擎在服务器端运行,但此视图中提供的终端控制台在客户端运行。

5.2. 客户端-服务器交互

大多数光束线都有“生产”Jython脚本,这些脚本完成光束线的核心工作。这些脚本包含最常用数据收集的逻辑-尽管它们的核心通常是常规的GDA扫描。

将这样的脚本与UI分离,可以将实验呈现给用户的方式从实际数据收集中分离出来。这两个部分可以单独开发,使得设计更加稳定、灵活和可维护。

本节概述了UI驱动Jython脚本以及与Jython脚本通信的不同方式。

5.2.1. 接口提供程序

提供对命令服务器(Jython服务器)的访问的单例对象。它使相同的代码能够通过一系列静电方法与此交互,无论是客户端还是服务器端。

这种设计使单元测试变得简单得多。它将所有功能分成几组方法,使您更容易找到需要的功能。您可能会发现最有用的功能是:

- CommandRunner
   - To run commands in the GDA Jython environment
- TerminalPrinter
   - To print to the Jython Console to provider user with progress
- JythonServerStatusProvider
   - To find out if scans or scripts are running
- ScanDataPointProvider
   - To be sent ScanDataPoints during a scan
- JythonNamespace
   - To fetch and put objects in the Jython namespace
   - Objects must be serializable!

有关每个接口提供的方法,请参见上面列出的各个接口的代码。

5.2.2. ScriptController

ScriptController是服务器端的分布式对象,用于特定脚本和驱动该脚本并希望从脚本返回进度信息或数据的UI部分之间的点对点通信。

该脚本由UI通过接口提供程序提供的CommandRunner启动(如上所述)。然后,脚本通过其update方法通过ScriptController将进度信息发送回UI。对这些消息感兴趣的UI部分应该通过Finder获取ScriptController对象引用,然后将自己注册为该ScriptController的IObserver。

如果UI希望看到扫描中的所有数据点,它应该使用接口提供程序提供的ScanDataPointProvider对象。

服务器配置:

<bean id="MyScriptController" class="gda.jython.scriptcontroller.ScriptControllerBase"/>

在客户端中,按照使用CORBA导出的方式使用Finder:

controller = Finder.find("MyScriptController")
controller.update("MyScript","<message you want to send>")

有关示例配置中的运行示例,请参见exampleScriptControllerScript.py和配置文件scriptController.xml。

5.2.3. 命令队列

与直接从UI运行脚本相比,这是一种改进。命令队列是一个分布式服务器端对象,它保存要运行的作业队列(序列)。这些作业通常是Jython命令(可以是简单命令,也可以是启动脚本),但也可以是其他对象。

命令队列提供了一个视图,该视图显示作业列表、控制按钮,并提供带有进度条和文本字段的反馈。要向用户提供更丰富的反馈,可以让脚本向Jython控制台提供输出;或者使用上面的ScriptController进行UI更新的特定部分;或者使用ScriptLog(如下所示)。

一个重要的配置选项是,当向命令队列添加项目时,命令队列是否应该自动启动(因此它的行为类似于命令缓冲区),或者它是否应该由用户手动启动,因此用户必须首先构建命令列表,然后才能启动队列。这是由FindableProcessorQueue的pauseWhenQueueEmpty布尔属性定义的。

Example-config中配置了一个命令队列来演示其用法。

要从UI驱动命令队列,请使用CommandProvider创建命令对象:

JythonCommandCommandProvider command =
   new JythonCommandCommandProvider("<command to run>","<command to display>",null)

然后使用CommandQueueViewFactory将命令添加到队列:

CommandQueueViewFactory.getQueue().addToTail(command)

您还可以通过编程方式与队列交互。例如:

CommandQueueViewFactory.getProcessor().start(100000)

在脚本中,您应该使用JythonScriptProgressProvider将更新发送到脚本中的命令队列:

from gda.commandqueue import JythonScriptProgressProvider
JythonScriptProgressProvider.sendProgress(int percent, String message)

5.2.4. 脚本日志

这是一个视图,它向用户提供脚本运行时间的历史记录,以及命令队列视图中显示的更多进度信息。如上所述,这将与执行光束线主数据收集的脚本一起使用。

它的工作方式是使用LoggingScriptController对象代替ScriptController。该类需要使用实现ScriptControllerLoggingMessage的消息bean从脚本向其提供进度信息。通过使用此接口,LoggingScriptController将消息存储在Derby数据库中。数据库中的历史记录允许UI中的脚本日志视图显示历史记录。

在示例config中有一个这方面的示例实现。运行example-config时,打开ScriptLog视图并运行“MessagingDemoScript”脚本以查看该视图中的输出。

5.3. 从实验的角度看

该透视图是针对重复运行使用大量参数定义的扫描的光束线的通用透视图。每次扫描的参数存储在一个或多个XML文件中。XML文件与数据一起存储,并由用户在UI中使用图形编辑器进行编辑。

扫描可以在多扫描中分组,并且XML文件可以存储在多个目录中。UI帮助用户组织他们的扫描。

扫描使用命令队列机制运行,进度显示在脚本日志视图中。

此功能由uk.ac.gda.client.exestentDefinition插件提供。

每种类型的XML文件都有自己的图形编辑器,并且每种编辑器背后都有一个Java bean。bean用于将参数传输到保存实验逻辑的Jython脚本。

XML文件提供实验选项的持久性,并存储在文件夹中,因此用户可以在访问光束线期间构建XML文件库。然后可以在后续访问中检索这些XML文件以重复实验。

Java bean、XML文件和编辑器之间的关系保存在GDAS RichBean框架中。使用这些对象的透视图大多是通用的,但对于此透视图的每个实现,都需要一些编码。有一些扩展点应该做出贡献。这里列出了操作实验透视图所需的特定于实现的类和选项。

5.3.1. 需要开发

要配置您自己的实验透视图实现,请执行以下操作:

  1. 必需的依赖项

    1. 您的插件需要依赖以下插件:

      - uk.ac.gda.common
      - uk.ac.gda.common.rcp
      - uk.ac.gda.client.experimentdefinition
      - org.eclipse.core.resources
      - org.dawnsci.common.widgets
      
    2. 它还需要是注册的好友 experimentdefinition 通过在MANIFEST.MF文件中包含以下行:

      Eclipse-RegisterBuddy: uk.ac.gda.client.experimentdefinition
      
  2. 创建Java Bean和相关编辑器

    这将定义你的实验。有关更多信息,请参见中的Javadoc uk.ac.gda.common.rcp/src/uk/ac/gda/richbeans/package-info.java 。bean必须实现 XMLRichBean .

    1. 编写Java bean,它将定义您的实验并导出该包。

    2. 编写一个组合,它将用作编辑bean和XML文件内容的UI。这必须使用组合的标准构造函数:(复合父项,int样式)。由于RichBean框架使用反射将bean属性映射到UI小部件,因此组合中必须有与bean中的getter匹配的方法名称。Composite getter必须返回扩展FieldComposite的RichBean小部件。这个组合也可以作为UI的独立部分包含在实验定义基础设施的睡觉之外的视图中。如果组合用于配置硬件,或者如果整个实验可以使用单个bean定义,这将非常有用。

    3. 编写用于将Java bean映射到XML的映射文件和XSD文件。实验对象的标记应与类名匹配。在每个Java bean类中,应该通过两个公共静电URL和两个方法引用这些URL:

      static public final URL mappingURL = MyBean.class.getResource("MyBeanMapping.xml");
      static public final URL schemaURL  = MyBean.class.getResource("MyBeanMapping.xsd");
      
      public static MyBean createFromXML(String filename) throws Exception {
              return (MyBean) XMLHelpers.createFromXML(mappingURL, MyBean.class, schemaURL, filename);
      }
      
      public static void writeToXML(MyBean scanParameters, String filename) throws Exception {
              XMLHelpers.writeToXML(mappingURL, scanParameters, filename);
      }
      
      1. 编写编辑器,它将显示组合和XML。此编辑器应该扩展ExperientBeanMultiPageEditor,因此将主要是样板:

      public final class MyBeanEditor extends RichBeanMultiPageEditorPart {
      
      @Override
      public Class<?> getBeanClass() {
              return MyBean.class;
      }
      
      @Override
      public URL getMappingUrl() {
              return MyBean.mappingURL;
      }
      
      @Override
      public RichBeanEditorPart getRichBeanEditorPart(String path, Object editingBean) {
              DelegatingRichBeanEditorPart editor = new DelegatingRichBeanEditorPart(path,getMappingUrl(),this,editingBean);
              editor.setEditorClass(MyBean.class);
              editor.setRichEditorTabText("Example Custom UI");
              return editor;
      }
      
      @Override
      public URL getSchemaUrl() {
              return MyBean.schemaURL;
      }
      

}

  1. 使用扩展点配置您的实验透视图。

    1. 对于每个bean类,向以下扩展点提供一个条目:

      1. uk.ac.common.beans.factory

      2. uk.ac.gda.richbeans.beantypes

      3. org.eclipse.core.contenttype.contentTypes

      4. org.eclipse.ui.Editor(编辑器id必须与Java类匹配,并且必须引用Content-type)

    2. 为这项事业贡献一份力量 uk.ac.gda.client.experimentdefinition 扩展点。它引用实验透视图用来执行某些角色的特定于实现的类。需要扩展以下抽象基类的类:

    1. 实验对象管理器--在多扫描中创建和管理实验

    2. 实验对象--扫描对象--保存对XML文件的引用

    3. AbstractValidator--用于在每次扫描中验证Bean中的值的逻辑

    1. 需要在插件中定义将每个bean类型的模板文件复制到工作目录的命令和处理程序。底层处理程序类始终是uk.ac.gda.client.experimentdefinition.ui.handlers.XMLCommandHandler,但是需要为每种bean类型分别提供org.eclipse.ui.Handler和org.eclipse.ui.Commands扩展点。

  2. 配置Command Queue,实验透视图使用它来运行扫描。在服务器中添加:

    <bean id="commandQueue" class="gda.commandqueue.CommandQueue">
    </bean>
    <bean id="commandQueueProcessor" class="gda.commandqueue.FindableProcessorQueue">
            <property name="queue" ref="commandQueue" />
            <property name="startImmediately" value="false" />
            <property name="pauseWhenQueueEmpty" value="true" />
            <property name="logFilePath" value="${gda.logs.dir}/commandQueueProcessor.log" />
    </bean>
    <bean class="uk.ac.gda.remoting.server.GdaRmiServiceExporter">
            <property name="serviceName" value="gda/commandQueueProcessor" />
            <property name="service" ref="commandQueueProcessor" />
            <property name="serviceInterface" value="gda.commandqueue.IFindableQueueProcessor" />
    </bean>
    <bean id="MyLoggingScriptController"
            class="gda.jython.scriptcontroller.logging.LoggingScriptController">
            <property name="messageClassToLog"
                    value="<an implementation specific bean implementing gda.jython.scriptcontroller.logging.ScriptControllerLoggingMessage>" />
            <property name="directory" value="${gda.var}/" />
            <property name="local" value="true"/>
    </bean>
    
    <bean class="uk.ac.gda.remoting.server.GdaRmiServiceExporter">
            <property name="serviceName" value="gda/MyLoggingScriptController" />
            <property name="service" ref="MyLoggingScriptController" />
            <property name="serviceInterface"
                    value="gda.jython.scriptcontroller.logging.ILoggingScriptController" />
    </bean>
    

    在客户端XML配置中:

    <bean id="MyLoggingScriptController" class="uk.ac.gda.remoting.client.GdaRmiProxyFactoryBean">
            <property name="serviceUrl" value="${gda.rmi.prefix}MyLoggingScriptController" />
            <property name="serviceInterface" value="gda.jython.scriptcontroller.logging.ILoggingScriptController" />
            <property name="refreshStubOnConnectFailure" value="true" />
    </bean>
    
    <bean id="commandQueueProcessor" class="uk.ac.gda.remoting.client.GdaRmiProxyFactoryBean">
            <property name="serviceUrl" value="${gda.rmi.prefix}commandQueueProcessor" />
            <property name="serviceInterface" value="gda.commandqueue.IFindableQueueProcessor" />
            <property name="refreshStubOnConnectFailure" value="true" />
    </bean>
    <bean class="gda.rcp.util.OSGIServiceRegister">
            <property name="class" value="gda.commandqueue.Processor" />
            <property name="service" ref="commandQueueProcessor" />
    </bean>
    <bean class="gda.rcp.util.OSGIServiceRegister">
            <property name="class" value="gda.commandqueue.Queue" />
            <property name="service" ref="commandQueueProcessor" />
    </bean>
    

配置好之后,实验透视图就可以包含在您自己的产品中,并且具有与示例产品中相同的管理XML文件和运行扫描的功能。

示例类位于uk.ac.gda.example插件的gda.example.richbean包中。