使用Openxal框架开发加速器模型相关的java应用程序
1 复制模板,并重命名
CSNS Openxal Github项目提供了开源的Openxal框架核心代码与一系列应用程序。在apps文件夹下可以找到”acceleratorapplicationtemplate“程序模板。我们在此基础上开发满足我们需求的加速器模型相关的java应用程序。
这里我们以”mysql2accelerator“程序的开发为例。
2 一个程序的资源文件夹构成:acceleratorapplicationtemplate为例
2.1 resources文件夹
该文件夹下保存了GUI设计相关的文件,一般是由”bricks“程序生成的xml文档”gui.bricks“。acceleratorapplicationtemplate程序开始运行时,将从该文件夹读取”gui.bricks“文件,然后自动地生成对应java程序窗口及窗口内控件。
2.2 src\xal\app\acceleratorapplicationtemplate文件夹
该文件夹下保存了程序核心的java类以及Main函数入口。我们在此模板基础上开发程序时,对Main.java和TemplateDocument.java的修改较少。
3 MVC设计模式
MVC的全名是Model View Controller,是模型(Model)-视图(view)-控制器(controller)的缩写,是一种设计模式。大多现有Openxal程序遵循这一设计模式,在此不加赘述。相关内容:MVC设计模式介绍
在”mysql2accelerator“程序的开发中,编写了以下几个类:
- Mysql2acceleratorController:定义GUI界面的后端功能和刷新行为。
- Mysql2acceleratorWindow:使用Java swing进行GUI前端窗口设计。
- SQL_dialog:继承于JDialog,配置对话框,用户将在对话框中输入MySQL数据库连接相关信息。
- SQLBaseDAO:SQL数据库的数据接口对象,定义了连接、查询、执行SQL语句等方法。
- SQLControllerModel:维护与SQL数据库的连接,将取得的数据转化为程序中需要的格式。
其他几个类分别是:
- Main:程序mysql2accelerator的Main函数入口
- ChannelMonitor:监控PV值变化,在PV值变化后立即更新对应表格中Live Value的数值。
- Mysql2acceleratorDocument:将程序状态保存为xml格式的文档,或从xml格式文档中恢复程序配置。
4 程序开发核心:模板中java文件修改与编写
4.1 对Main.java的修改
- 程序可读文档拓展名定义:此处的文档指的是保存程序状态的xml格式的文档,此处定义”mysql2accelerator“程序文档的拓展名为m2a,当然也可以是任何自定义的符合规则的拓展名。
public String[] readableDocumentTypes() {
return new String[] {"m2a"};
}
- 程序可写文档拓展名定义:所指文档同上
public String[] writableDocumentTypes() {
return new String[] {"m2a"};
}
- 定义应用名:
public String applicationName() {
return "Mysql2Accelerator";
}
4.2 对TemplateDocument.java的修改
首先重命名为合适的名称,Mysql2acceleratorDocument.java。
- 自定义选中的sequence改变后执行的行为,这里执行updateAcceleratorTableView(),将会更新Accelerator Table显示的数据。
/** 选中的sequence改变后执行的行为 */
public void selectedSequenceChanged() {
if (selectedSequence != null) {
System.out.println("Sequence selected: " + selectedSequence.getId());
APP_CONTROLLER.updateAcceleratorTableView();
setHasChanges(true);
}
}
4.4 对TemplateWindow.java的修改
这一文件定义了程序前端界面构成与组件排布。在我们的开发中,删除了原有的内容,使用Java Swing编写了程序的前端界面。Swing 是一个为Java设计的GUI工具包,Swing是JAVA基础类的一部分,包括了图形用户界面(GUI)器件如:文本框,按钮,分隔窗格和表。现有的Openxal程序的前端窗口和控件大多属于Swing。(Swing 介绍)
将TemplateWindow.java重命名为Mysql2acceleratorWindow.java。具体代码如下:
package xal.app.mysql2accelerator;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
/**
* GUI前端设计。继承于JPanel,将添加到Openxal框架中预先配置好的加速器程序窗口"xal.extension.application.smf.DefaultAcceleratorWindow"中去。
* @ClassName Mysql2acceleratorWindow
* @Description GUI前端设计。继承于JPanel,将添加到Openxal框架中预先配置好的加速器程序窗口"xal.extension.application.smf.DefaultAcceleratorWindow"中去。
* @author Fangnan Li
* @date 2022-04-06 14:50
*
*/
class Mysql2acceleratorWindow extends JPanel {
/** serialization ID */
private static final long serialVersionUID = 1L;
private JTable Database_Table;
private JTable Accelerator_Table;
private JButton Link_to_MySQL_Button;
private JButton Refresh_Database_Button;
private JButton Send_Data_Button;
private JButton Check_All_Button;
private JButton Uncheck_All_Button;
/** Creates a new instance of MainWindow */
public Mysql2acceleratorWindow() {
super();
this.setBorder(new EmptyBorder(5, 5, 5, 5));
this.setLayout(new BorderLayout(0, 0));
JPanel Above_Box = new JPanel();
Above_Box.setBorder(new EmptyBorder(10, 10, 10, 10));
this.add(Above_Box, BorderLayout.NORTH);
Above_Box.setLayout(new BoxLayout(Above_Box, BoxLayout.X_AXIS));
Link_to_MySQL_Button = new JButton("Link to MySQL");
Above_Box.add(Link_to_MySQL_Button);
Component horizontalGlue_2 = Box.createHorizontalGlue();
Above_Box.add(horizontalGlue_2);
JPanel Below_Box = new JPanel();
Below_Box.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10), new EtchedBorder(EtchedBorder.LOWERED, null, null)));
Below_Box.setBounds(new Rectangle(10, 10, 10, 10));
this.add(Below_Box, BorderLayout.CENTER);
Below_Box.setLayout(new BoxLayout(Below_Box, BoxLayout.X_AXIS));
JSplitPane Split_Pane = new JSplitPane();
Split_Pane.setResizeWeight(0.58);
Below_Box.add(Split_Pane);
Box Database_Box = Box.createHorizontalBox();
Database_Box.setBorder(new EmptyBorder(3, 3, 3, 3));
Database_Box.setBounds(new Rectangle(0, 0, 500, 0));
Split_Pane.setLeftComponent(Database_Box);
Box Database_Data_Box = Box.createVerticalBox();
Database_Box.add(Database_Data_Box);
JPanel Left_Control_Box = new JPanel();
Database_Data_Box.add(Left_Control_Box);
Left_Control_Box.setLayout(new BoxLayout(Left_Control_Box, BoxLayout.X_AXIS));
Refresh_Database_Button = new JButton("Refresh");
Left_Control_Box.add(Refresh_Database_Button);
Component horizontalGlue_1 = Box.createHorizontalGlue();
Left_Control_Box.add(horizontalGlue_1);
JScrollPane Left_Table_Box = new JScrollPane();
Left_Table_Box.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
Database_Data_Box.add(Left_Table_Box);
Database_Table = new JTable();
Left_Table_Box.setViewportView(Database_Table);
Box Send_Data_Box = Box.createHorizontalBox();
Database_Box.add(Send_Data_Box);
Send_Data_Button = new JButton(">>");
Send_Data_Box.add(Send_Data_Button);
Box Accelerator_Box = Box.createVerticalBox();
Accelerator_Box.setBorder(new EmptyBorder(3, 3, 3, 3));
Accelerator_Box.setBounds(new Rectangle(0, 0, 500, 0));
Split_Pane.setRightComponent(Accelerator_Box);
JPanel Right_Control_Box = new JPanel();
Accelerator_Box.add(Right_Control_Box);
Check_All_Button = new JButton("Check All");
Check_All_Button.setHorizontalAlignment(SwingConstants.RIGHT);
Uncheck_All_Button = new JButton("Uncheck All");
Uncheck_All_Button.setHorizontalAlignment(SwingConstants.RIGHT);
Right_Control_Box.setLayout(new BoxLayout(Right_Control_Box, BoxLayout.X_AXIS));
Component horizontalGlue = Box.createHorizontalGlue();
Right_Control_Box.add(horizontalGlue);
Right_Control_Box.add(Check_All_Button);
Right_Control_Box.add(Uncheck_All_Button);
JScrollPane Right_Table_Box = new JScrollPane();
Right_Table_Box.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
Accelerator_Box.add(Right_Table_Box);
Accelerator_Table = new JTable();
Right_Table_Box.setViewportView(Accelerator_Table);
}
public JTable get_Database_Table() {
return Database_Table;
}
public JTable get_Accelerator_Table() {
return Accelerator_Table;
}
public JButton get_Link_to_MySQL_Button() {
return Link_to_MySQL_Button;
}
public JButton get_Refresh_Database_Button() {
return Refresh_Database_Button;
}
public JButton get_Send_Data_Button() {
return Send_Data_Button;
}
public JButton get_Check_All_Button() {
return Check_All_Button;
}
public JButton get_Uncheck_All_Button() {
return Uncheck_All_Button;
}
}
以上代码生成的窗口效果如下图所示:
4.4.1 Java Swing的GUI开发工具:WindowBuilder
WindowBuilder是eclipse中的插件,通过拖动控件设计GUI界面,所见即所得。上述Java代码便是使用WindowBuilder设计后自动生成的。
WindowBuilder安装教程,在线安装或离线包下载安装都可:windowBuilder最新的安装教程
5 程序开发核心:自定义类和功能
5.1 Mysql数据库相关
5.1.1 SQL数据库的数据接口对象:SQLBaseDAO.java
修饰符和类型 | 方法 | 说明 |
---|---|---|
void | closeConnection() | 关闭与Mysql数据库的连接 |
ResultSet | executeQuery(String sql, String[] paras) | 执行SQL数据查询 |
int | executeUpdate(String sql, String[] paras) | 执行SQL语句,增删查改 |
void | getConnection() | 连接数据库 |
boolean | isConnectionAvailable() | 返回数据库连接是否可用 |
5.1.2 对话框,输入MySQL数据库连接相关信息:SQL_dialog.java
继承于JDialog。定义了对话框的内容,如下所示:
用于获取用户输入,然后根据相关信息建立与MySQL数据库的连接。
如果连接失败,将弹出如下的对话框提示。失败可能有许多原因:输入信息错误、MySQL数据库服务端错误、网络连接错误等等。
若成功连接,在左侧的列表中将显示读回的数据。这一数据显示功能由SQLControllerModel.java和Mysql2acceleratorController.java完成。
5.1.3 维护与SQL数据库的连接,将取得的数据转化为程序中需要的格式:SQLControllerModel.java
负责实例化SQL_dialog对象,从对话框中获取用户输入的信息,然后利用这些信息建立与SQL数据库的连接。这一类中的主要方法有:
修饰符和类型 | 方法 | 说明 |
---|---|---|
void | closeSQLConnection() | 关闭连接 |
Vector | getColumnNames() | 返回查询到数据表的列名 |
void | getSQLConnection() | 与SQL数据库连接 |
Vector | getTableData() | 返回查询到数据表的表中数据 |
boolean | isConnectionPrepared() | 检查是否数据库的连接可用 |
private void | updateValues() | 从对话框中获取的IP、PORT、USER、PASS、DBNAME、TABLENAME等数据 |
5.2 Mysql2acceleratorController.java
是程序功能实现最核心的部分。设置GUI界面的后端功能,定义各个按钮控件的点击事件、Table等数据展示控件的数据更新行为。
主要方法包括:
修饰符和类型 | 方法 | 说明 |
---|---|---|
private void | configure_Link_to_MySQL_Button(xal.extension.bricks.WindowReference windowReference) | 定义Link to MySQL按钮事件,即打开对话框,等待用户输入MySQL相关连接配置 |
private void | configureCheckAllButton(xal.extension.bricks.WindowReference windowReference) | 定义Check All按钮事件,即选中加速器表格中的所有node |
void | configureMainWindow(xal.extension.bricks.WindowReference windowReference) | 为程序主界面MainWindow添加控件 |
private void | ConfigureSendDataButton(xal.extension.bricks.WindowReference windowReference) | 初始化窗口时调用,定义窗口中间的">>" Send Data按钮事件 |
private void | configureUncheckAllButton(xal.extension.bricks.WindowReference windowReference) | 定义Uncheck All按钮事件,即取消选中加速器表格中的所有node |
private void | makeAcceleratorTableView(xal.extension.bricks.WindowReference windowReference) | 初始化窗口时调用,配置展示加速器相关数据的表格 |
private void | makeDatabaseView(xal.extension.bricks.WindowReference windowReference) | 初始化窗口时调用,配置展示数据库数据的表格,定义Refresh按钮事件 |
void | updateAcceleratorTableView() | 更新加速器表格中的数据,一般在切换sequence后调用 |
void | updateDatabaseView() | 更新数据库表格中的数据,表格列宽自适应相关配置 |
5.3 读取和设置磁铁电流的方法
xal.smf.impl.Electromagnet是 xal.smf.AcceleratorNode的子类。在加载xal配置文件的时候,所有Node类都被实例化。我们调用Electromagnet的getMainSupply()方法,获取磁铁对应电源对象MagnetMainSupply。
- 调用MagnetMainSupply的getCurrent()方法读取电流值。
- 调用MagnetMainSupply的setCurrent(double val)方法设置电流值。
此外,值得一提的是,MagnetMainSupply类还提供了getField()、setField(double newField)、getChannel( final String handle )等方法。
6 程序功能介绍
本程序的主要功能是将MySQL数据库中保存的参数数据,设置到加速器EPICS控制系统的相应PV中去。设置的参数可选可调整,被设置的设备可选择,实时值也在程序中实时更新显示。目前设置的所有设备均为电磁铁,设置PV量为磁铁电流。
6.1 根据用户输入连接并获取MySQL中的数据表
6.2 数据库连接失败提示
6.3 自适应的列宽,避免列宽过小
-
列数少时,充满Panel
-
列数多时,出现横向滚动条
6.4 数据库列表支持数据修改,便于参数设置的微调,但不影响数据库中数据
6.5 加速器参数列表
根据加载的xal加速器配置文件和选中的sequence,显示加速器信息列表。列表包含加速器Node名称、类型、位置、PV值类型、实时值、设置的PV名等信息。
6.8 Check All与Unheck All按钮:全选或取消全选需要设置的Node
6.7 选中MySQL数据表中的一条数据,发布给CheckBox选中的Node,即设置相应PV
MySQL数据表的列名即为Node ID,对应于加速器列表中的Node ID。点击窗口中部的“>>”按钮,设置EPICS控制系统对应PV值(Node名、PV名等参数在xal配置文件中设置)。
若加速器表中的Node不在数据库表中,则console窗口出现信息提示:
若设置的数据包含空值或错误格式,console窗口则会提示:
7 注释及javadoc文档的生成
根据特定格式的注释,能够自动化地生成程序的javadoc文档。在eclipse中,通过菜单栏的File->Export->Java->javadoc生成javadoc文档。
文档为一系列html格式的文件,如下图所示。
生成的文档为html格式,可在浏览器中打开,内容包含项目结构、程序包、类、方法、变量的总结和描述。
7.1 注释格式
为了生成javadoc文档,需按照特定格式编写注释。主要对类、方法、变量的功能描述进行注释。一下只是一种举例,可以按照自己的需求规定注释格式,一般只需保证一个项目使用相同的注释格式、注释模板。(Javadoc详解)
-
类的注释
-
方法注释,方法可能由传入参数,也可能没有传入参数,以下是这两种情况注释的举例。
-
变量注释
Last
Feel free to contact us by email: fnli@stu.pku.edu.cn