TWeaver Quick-Start
2016-04-30 12:14
567 查看
官网quick-start
运行图见官方,或者自己运行一下
Alt + Shift + R,在Eclipse中重命名文件
1).new一个容器对象TDataBox、一个画布对象TNetwork;
2).把TNetwork放置在面板中,并布局设置大小;
3).new若干图元(Node、Link等)并add到Box容器中;
下面创建了一个“两点一线”的简单图形:
首先要创建一个tree组件,然后与前面的DataBox实例进行连接。这样,拓扑图和树就共享了一套DataBox中的数据。然后,将树放在窗口分隔条的左侧。这样,树创建就完成了,前面创建的对象会直接显示在树上面。为了生动起见,我们又创建两个Dummy对象,把数据进行了一些分层,使得tree层次更加生动容易理解。
用API创建设备面板
要用API创建设备面板,我们首先需要做一些工作:
创建一个新的Chassis对象,并将其放入节点A(也就是作为节点A的孩子);
创建一个机架对象,放入Chassis对象(作为Chassis对象的孩子);
创建一些端口对象,放入机架中(作为机架的孩子);
以下我们给出了相关代码。按照前面的思路new这些对象,然后放入DataBox中即可。我们创建16个以太网口的交换机,放置在面板的适当位置。这些代码稍微多一点,但是逻辑都极其简单,我们将其放入函数step3
我们在拓扑图上用鼠标双击节点A,拓扑图会自动进入我们上面创建的机架图;双击拓扑图的空白区域,可以返回上层拓扑图。节点A作为设备节点,Chassis对象代表一个机架图,Rack代表物理机架,而这些端口对象则代表了设备上的具体以太网端口
用XML创建机架图
上一节介绍了使用API编程的方式用代码来创建机架图。由于每个设备的外观、结构千差万别,如果正在开发一套综合网管系统,需要管理上百种不同厂商的设备,则这个工作就显得非常啰嗦,代码量很大,也不容易维护。这时,可以考虑用XML的方式来简化代码。这节我们同样做上一节所做的工作,只是换成了XML的方式。
首先我们准备设备面板的模版文件,也就是XML文件。我们可以通过TWaver产品Demo提供的编辑器进行编辑,然后导出。为了简化,我们直接给出和上节面板相同数据的XML文件,如下
然后,我们把它保存在文件equipment1_template.xml中。最后,通过以下代码进行加载
上述代码还是创建一个Chassis对象,但是把XML模版文件名直接作为属性,设置给Chassis对象即可。具体机架图上的数据不再需要用代码创建。直接运行上述代码,可以看到和上一节一模一样的效果。可见,适当的采用XML方式,可以大幅的减少代码工作量;同时,这个XML也便于修改、维护、存储、交换。
注意:上述代码运行时,在双击节点A之前,机架图数据实际并未加载进DataBox中;当鼠标第一次双击节点A时,TWaver检查Chassis状态是否数据已经加载,如果未加载则从XML中进行读取解析加载,否则直接显示机架图内容。这也是TWaver另外一个重要特性:延迟加载机制。关于延迟加载方面的细节,请看后续章节介绍。
可见,通过XML可以获得如下一些好处:
1 过XML和延迟加载机制,可以加速程序启动速度。想象一下,如果有1000个节点,每个节点都有一套复杂的机架图,则完全通过API来加载,程序启动将非常缓慢,也没有必要在程序启动就创建所有的数据。通过延迟加载,首先显示必须显示的节点数据,当双击查看下层面板细节时,再通过XML获取细节数据。这样可以大幅优化程序的效率。
2 化代码:把相对固定的数据放入XML作为数据模版,可以大幅减少代码的编写数量,便于维护、存储、修改、交换。
3 低内存消耗:通过XML实现”按需加载”的机制,只创建需要的数据,可以节省内存消耗,降低数据的创建数量。
4 据共享:通过定义数据模版,可以实现数据在前后台、多程序间的共享。
菜单生成器是一个接口,被设置在拓扑图或其他图形组件上。一旦设置,当鼠标右键点击图形组件时,TWaver就会回调这个接口获得右键菜单。TWaver会将当前的一些操作场景传入,例如被点击的图形组件、鼠标事件等等。我们要做的,就是根据这些信息,动态的生成需要的右键菜单,返回即可。具体的菜单显示等细节,TWaver会帮我们完成。
为了演示,我们在例子中添加一个双击动作,弹出消息框显示被双击的数据对象。这段代码被封装在函数step5中
运行程序如下图。双击空白区和双击对象,都会弹出消息。
此外,为了方便开发者监听鼠标事件,TWaver添加了经过封装的鼠标监听方法:
TNetwork.addElementDoubleClickedActionListener:添加Element双击事件监听器。
TNetwork.addBackgroundDoubleClickedActionListener:添加空白区域双击事件监听器。
TNetwork.addElementClickedActionListener:添加Element单击事件监听器。
通过这些高度封装的方法,监听鼠标事件就更加方便了。
控制选择;
监听选择变化;
移动拓扑图以便选中数据处于可见位置;
由于选择容器是DataBox的一个组成部分,所以所有共享同一个DataBox的图形组件也共享同一套数据选择状态。也就是说,一个对象被选择,是在数据层决定的,它在所有与DataBox相连的图形组件上都会体现出来。如果对选择变化进行监听,则从DataBox的选择容器进行加装监听器。每次选择发生变化,事件会被发送到所有监听器。我们可以在监听器中写代码执行各种任务。
为了展示这个功能,我们创建一个监听器,当用户从tree选择一个数据后,拓扑图也会显示选中数据,并且如果这个选中的数据不在可见区域内,会自动滚动画布以保证数据处于可见视野内。
每一个Element对象都有一个告警状态表Alarm State。这是一个告警信息表,记录了所有发生在Element上面的告警信息。要为数据添加告警,首先要获得告警状态表,然后在其中添加告警信息即可。数据会在拓扑图、树等图形组件上做出相应的显示变化。
另外,还可以使用DataBox提供的告警传播机制。TWaver默认提供了一个功能完善的告警传播器,可以将告警沿着父对象的路径进行传播。也可以编写符合自己业务规则的告警传播器,设置在DataBox上使用。
这里,我们对前面创建的数据添加一些告警,代码被封装在step7函数中。
TWaver默认提供了一些预定义的装饰图标,可以直接使用。这些都被IconAttachmentHolder类进行统一管理。扩展新的装饰图标也很简单。我们通过代码进行演示如何操作。首先,我们需要一个小图标: icon,然后我们定义一个新的装饰图标并进行注册,然后让它显示在某一个Element上面。装饰图标从IconAttachment进行继承,我们重载构造函数,指定我们的图标即可。新的装饰图标需要是一个顶级类,我们推荐用public static来定义,或者放入单独的一个文件中TUIManager.registerAttachment方法进行注册,这样在运行过程中,就可以用element.addAttachment方法显示装饰图标了。
单击中间的Link会显示加粗
运行图见官方,或者自己运行一下
Alt + Shift + R,在Eclipse中重命名文件
第一个例子
TWaver绘制网元的一般过程如下:1).new一个容器对象TDataBox、一个画布对象TNetwork;
2).把TNetwork放置在面板中,并布局设置大小;
3).new若干图元(Node、Link等)并add到Box容器中;
下面创建了一个“两点一线”的简单图形:
import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.WindowConstants; import twaver.Link; import twaver.Node; import twaver.TDataBox; import twaver.TWaverUtil; import twaver.network.TNetwork; public class FirstDemo extends JFrame{ private TDataBox box = new TDataBox("First Data Box");//创建DataBox容器 private TNetwork network = new TNetwork(box);//创建可视化视图组件,会显示上面的工具栏 // network.setToolbarByName(""); //这句话可以把工具栏去掉 private JPanel networkPanel = new JPanel(new BorderLayout()); public FirstDemo() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); getContentPane().add(networkPanel,BorderLayout.CENTER); networkPanel.add(network, BorderLayout.CENTER); doSample(); } public static void main(String[] args) { FirstDemo frame = new FirstDemo(); frame.setSize(600,400); frame.setTitle("TWaver Tutorial"); TWaverUtil.centerWindow(frame); frame.setVisible(true); } private void doSample() { Node from = new Node("from"); from.setName("I Am from"); from.setLocation(50,50); //不加坐标会挤到左上角 box.addElement(from); // 加两个Node Node to = new Node("to"); to.setName("I Am to"); to.setLocation(500,260); box.addElement(to); // 加一条线 Link link = new Link(from, to); link.setName("Telephone Line"); box.addElement(link); } }
例子程序
首先,我们创建一个窗体,然后放入一个分隔条。下面我们开始动手。我们用函数doSample中封装各种TWaver初始化动作import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import twaver.*; import twaver.network.*; import twaver.network.ui.*; import twaver.table.*; import twaver.tree.*; public class Tutorial extends JFrame { private TDataBox box = new TDataBox("Simple Data Box"); private TNetwork network; private TTree tree; private JPanel networkPane = new JPanel(new BorderLayout()); private JPanel treePane = new JPanel(new BorderLayout()); private JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePane, networkPane); public Tutorial() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); getContentPane().add(split, BorderLayout.CENTER); split.setDividerLocation(200); //不加的话,左边的框显示不出来 doSample(); } public static void main(String[] args) { Tutorial frame = new Tutorial(); frame.setSize(500, 300); frame.setTitle("TWaver Tutorial"); TWaverUtil.centerWindow(frame); frame.setVisible(true); } private void doSample() { try { step1(); step2(); step3(); step4(); step5(); step6(); step7(); step8(); step9(); } catch (Exception ex) { ex.printStackTrace(); } } private void step1() { } private void step2() { } private void step3() { } private void step4() { } private void step5() { } private void step6() { } private void step7() { } private void step8() { } private void step9() { } }
step1 创建简单拓扑图
要让拓扑图正常工作,首先需要创建一个DataBox来装载数据。然后创建拓扑图组件与之相连。接下来,把拓扑图放入窗体中。最后,创建两个节点一个连线,放入DataBoxprivate void step1() { network = new TNetwork(box); networkPane.add(network, BorderLayout.CENTER); Node nodeA = new Node("A"); nodeA.setName("I'm node A!"); nodeA.setLocation(50, 50); box.addElement(nodeA); Node nodeB = new Node("B"); nodeB.setName("I'm node B!"); nodeB.setLocation(200, 200); box.addElement(nodeB); Link link = new Link("link", nodeA, nodeB); link.setName("Telephone Line"); }
step2 创建树组件
这节介绍如何创建一个树组件,用来显示拓扑图中数据的层次结构,也就是其包含关系。一般的应用程序都会用树和拓扑图协同工作,综合显示数据的外观和层次结构。首先要创建一个tree组件,然后与前面的DataBox实例进行连接。这样,拓扑图和树就共享了一套DataBox中的数据。然后,将树放在窗口分隔条的左侧。这样,树创建就完成了,前面创建的对象会直接显示在树上面。为了生动起见,我们又创建两个Dummy对象,把数据进行了一些分层,使得tree层次更加生动容易理解。
private void step2() { Dummy nodeDummy = new Dummy("node dummy"); nodeDummy.setName("All Nodes"); nodeDummy.addChild(box.getElementByID("A")); nodeDummy.addChild(box.getElementByID("B")); box.addElement(nodeDummy); Dummy linkDummy = new Dummy("link dummy"); linkDummy.setName("All Links"); linkDummy.addChild(box.getElementByID("link")); box.addElement(linkDummy); // 只是用来分类,不加这两个Dummy会把Node和Link放到一块 tree = new TTree(box); JScrollPane scroll = new JScrollPane(tree); treePane.add(scroll, BorderLayout.CENTER); // 这里要套一个scrollpane,nodepane没套是因为TNetwork已经有了 }
step3 显示设备面板
电信网管系统中,经常要显示电信设备的面板图或者机架图,便于直接监控设备的运行状况。本节介绍如何创建设备面板,并呈现在拓扑图中。我们会用到API和XML两种方式创建数据,供读者参考。用API创建设备面板
要用API创建设备面板,我们首先需要做一些工作:
创建一个新的Chassis对象,并将其放入节点A(也就是作为节点A的孩子);
创建一个机架对象,放入Chassis对象(作为Chassis对象的孩子);
创建一些端口对象,放入机架中(作为机架的孩子);
以下我们给出了相关代码。按照前面的思路new这些对象,然后放入DataBox中即可。我们创建16个以太网口的交换机,放置在面板的适当位置。这些代码稍微多一点,但是逻辑都极其简单,我们将其放入函数step3
private void step3() { Node node = (Node) box.getElementByID("A"); Chassis chassis = new Chassis("Chassis A"); node.addChild(chassis); box.addElement(chassis); //1.在chassis上添加机架 Rack rack = new Rack("Rack A"); rack.setName("Rack"); rack.setLocation(50, 50); rack.setImage("/demo/resource/tutorial/rack.png"); chassis.addChild(rack); box.addElement(rack); //2.在机架上添加端口 String imgPort1 = "/demo/resource/tutorial/port1.png"; String imgPort2 = "/demo/resource/tutorial/port2.png"; for (int module = 0; module < 4; module++) { Dummy dummy = new Dummy("PortDummy" + module); dummy.setName("module" + module); rack.addChild(dummy); box.addElement(dummy); for (int index = 0; index < 4; index++) { Port port = new Port(module + ":" + index); int x, y; if (module % 2 == 0) { x = 210 + index * 24; } else { x = 319 + index * 24; } if (module < 2) { y = 16; port.setImage(imgPort1); } else { y = 37; port.setImage(imgPort2); } x += rack.getLocation().x; y += rack.getLocation().y; port.setLocation(new Point(x, y)); dummy.addChild(port); box.addElement(port); } } }
我们在拓扑图上用鼠标双击节点A,拓扑图会自动进入我们上面创建的机架图;双击拓扑图的空白区域,可以返回上层拓扑图。节点A作为设备节点,Chassis对象代表一个机架图,Rack代表物理机架,而这些端口对象则代表了设备上的具体以太网端口
用XML创建机架图
上一节介绍了使用API编程的方式用代码来创建机架图。由于每个设备的外观、结构千差万别,如果正在开发一套综合网管系统,需要管理上百种不同厂商的设备,则这个工作就显得非常啰嗦,代码量很大,也不容易维护。这时,可以考虑用XML的方式来简化代码。这节我们同样做上一节所做的工作,只是换成了XML的方式。
首先我们准备设备面板的模版文件,也就是XML文件。我们可以通过TWaver产品Demo提供的编辑器进行编辑,然后导出。为了简化,我们直接给出和上节面板相同数据的XML文件,如下
<?xml version="1.0" encoding="UTF-8"?> <java version="1.4.1" class="java.beans.XMLDecoder"> <!-- rack --> <object class="twaver.Rack" id="rack"> <void property="Image"> <string>/image/twaverRack.png</string></void> <void property="location"> <object class="java.awt.Point"> <int>100</int> <int>100</int> </object> </void> </object> <!-- ports --> <!-- console port --> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverConsolePort.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>259</int><int>145</int> </object> </void> </object> <!-- fiber port --> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverFiberPort.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>582</int><int>132</int> </object> </void> </object> <!-- module 1--> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>310</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>334</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>358</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>382</int><int>116</int> </object> </void> </object> <!-- module 2--> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>419</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>443</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>467</int><int>116</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort1.png</string> </void> <void property="parent"> <object idref="rack"/></void> <void property="location"> <object class="java.awt.Point"> <int>491</int><int>116</int> </object> </void> </object> <!-- module 3--> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>310</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>334</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>358</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>382</int><int>137</int> </object> </void> </object> <!-- module 4--> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>419</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>443</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>467</int><int>137</int> </object> </void> </object> <object class="twaver.Port"> <void property="Image"> <string>/image/twaverPort2.png</string> </void> <void property="parent"> <object idref="rack"/> </void> <void property="location"> <object class="java.awt.Point"> <int>491</int><int>137</int> </object> </void> </object> </java>
然后,我们把它保存在文件equipment1_template.xml中。最后,通过以下代码进行加载
private void step3() { //add chassis to node A. Node node = (Node) box.getElementByID("A"); Chassis chassis = new Chassis("Chassis A"); chassis.setDataSource("/equipment1_template.xml"); node.addChild(chassis); box.addElement(chassis); }
上述代码还是创建一个Chassis对象,但是把XML模版文件名直接作为属性,设置给Chassis对象即可。具体机架图上的数据不再需要用代码创建。直接运行上述代码,可以看到和上一节一模一样的效果。可见,适当的采用XML方式,可以大幅的减少代码工作量;同时,这个XML也便于修改、维护、存储、交换。
注意:上述代码运行时,在双击节点A之前,机架图数据实际并未加载进DataBox中;当鼠标第一次双击节点A时,TWaver检查Chassis状态是否数据已经加载,如果未加载则从XML中进行读取解析加载,否则直接显示机架图内容。这也是TWaver另外一个重要特性:延迟加载机制。关于延迟加载方面的细节,请看后续章节介绍。
可见,通过XML可以获得如下一些好处:
1 过XML和延迟加载机制,可以加速程序启动速度。想象一下,如果有1000个节点,每个节点都有一套复杂的机架图,则完全通过API来加载,程序启动将非常缓慢,也没有必要在程序启动就创建所有的数据。通过延迟加载,首先显示必须显示的节点数据,当双击查看下层面板细节时,再通过XML获取细节数据。这样可以大幅优化程序的效率。
2 化代码:把相对固定的数据放入XML作为数据模版,可以大幅减少代码的编写数量,便于维护、存储、修改、交换。
3 低内存消耗:通过XML实现”按需加载”的机制,只创建需要的数据,可以节省内存消耗,降低数据的创建数量。
4 据共享:通过定义数据模版,可以实现数据在前后台、多程序间的共享。
step4 设置右键菜单
右键菜单是一个非常常用的交互方法,通过对数据进行选择、右键菜单,可以快速调出上下文有关的操作选项,为软件使用者提供直观的交互方法。TWaver中,我们使用一个叫做弹出菜单生成器(PopupMenuGenerator)的接口,来制作各种不同的右键菜单。更多关于使用右键菜单的例子,请见后续章节。这里仅给出一个简单的例子,让读者了解弹出菜单是如何制作出来的。菜单生成器是一个接口,被设置在拓扑图或其他图形组件上。一旦设置,当鼠标右键点击图形组件时,TWaver就会回调这个接口获得右键菜单。TWaver会将当前的一些操作场景传入,例如被点击的图形组件、鼠标事件等等。我们要做的,就是根据这些信息,动态的生成需要的右键菜单,返回即可。具体的菜单显示等细节,TWaver会帮我们完成。
private void step4() { //Create a popup menu generator PopupMenuGenerator popupMenuGenerator = new PopupMenuGenerator() { /** * Add the identifier of each of the selected objects to the menu. * In this example, the items added to the menu do nothing. * In a real application, you would probably associate an * implementation of the Swing Action interface with each menu item. */ public JPopupMenu generate(TView tview, MouseEvent mouseEvent){ //Create an empty pop-up menu. JPopupMenu popMenu = new JPopupMenu(); JMenuItem item; //If the selectedObjects collection is empty, no objects are selected. if (tview.getDataBox().getSelectionModel().isEmpty()) { popMenu.add("Nothing selected"); } else { //Access the selected objects from the selection model. Iterator it = tview.getDataBox().getSelectionModel().selection(); while (it.hasNext()) { Element element = (Element) it.next(); popMenu.add(element.getName()); } } //If menu is empty, return null. if (popMenu.getComponentCount() == 0) { return null; } else { return popMenu; } } }; //Set the pop-up menu generator for network components network.setPopupMenuGenerator(popupMenuGenerator); }
step5 添加鼠标和键盘动作
拓扑图是在Java Swing组件的扩展上扩展出来的,和其他Swing组件一样,在Network上添加鼠标、键盘事件是很容易的。唯一需要注意的是,拓扑图并非一个简单JComponent,它由工具条、滚动窗口、画布等部分组成。所以,实际上我们一般添加动作都是针对于画布的,而不是Network本身。所以,要使用network.getCanvas()方法先获得画布对象,然后就可以像其他Swing组件那样添加各种监听器了。为了演示,我们在例子中添加一个双击动作,弹出消息框显示被双击的数据对象。这段代码被封装在函数step5中
private void step5() { network.getCanvas().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { //获取双击的网元对象 Element element = network.getElementPhysicalAt(e.getPoint()); String message; if (element == null) { message = "You clicked nothing."; } else { message = "You clicked '" + element.getName() + "'"; } JOptionPane.showMessageDialog(network, message); } } }); }
运行程序如下图。双击空白区和双击对象,都会弹出消息。
此外,为了方便开发者监听鼠标事件,TWaver添加了经过封装的鼠标监听方法:
TNetwork.addElementDoubleClickedActionListener:添加Element双击事件监听器。
TNetwork.addBackgroundDoubleClickedActionListener:添加空白区域双击事件监听器。
TNetwork.addElementClickedActionListener:添加Element单击事件监听器。
通过这些高度封装的方法,监听鼠标事件就更加方便了。
step6 处理数据选择
这一节将介绍如下内容:控制选择;
监听选择变化;
移动拓扑图以便选中数据处于可见位置;
由于选择容器是DataBox的一个组成部分,所以所有共享同一个DataBox的图形组件也共享同一套数据选择状态。也就是说,一个对象被选择,是在数据层决定的,它在所有与DataBox相连的图形组件上都会体现出来。如果对选择变化进行监听,则从DataBox的选择容器进行加装监听器。每次选择发生变化,事件会被发送到所有监听器。我们可以在监听器中写代码执行各种任务。
为了展示这个功能,我们创建一个监听器,当用户从tree选择一个数据后,拓扑图也会显示选中数据,并且如果这个选中的数据不在可见区域内,会自动滚动画布以保证数据处于可见视野内。
private void step6() { //create a selection listener. DataBoxSelectionListener listener = new DataBoxSelectionListener() { public void selectionChanged(DataBoxSelectionEvent e) { //get the last selected element and make it visible. Element element = e.getBoxSelectionModel().lastElement(); if (element != null) { network.ensureVisible(element); } } }; box.getSelectionModel().addDataBoxSelectionListener (listener); } private void step7() { }
step7 添加告警
这一节介绍如何在数据上使用告警。TWaver提供了综合、全面、强大的告警支持,以简化电信管理软件的开发复杂度。TWaver提供了许多关于告警方面的图形渲染属性,用于控制告警的呈现。当告警发生后,对应的数据就会以相应的方式进行绘制和渲染,以便用直观、易于理解的方式提醒用户。每一个Element对象都有一个告警状态表Alarm State。这是一个告警信息表,记录了所有发生在Element上面的告警信息。要为数据添加告警,首先要获得告警状态表,然后在其中添加告警信息即可。数据会在拓扑图、树等图形组件上做出相应的显示变化。
另外,还可以使用DataBox提供的告警传播机制。TWaver默认提供了一个功能完善的告警传播器,可以将告警沿着父对象的路径进行传播。也可以编写符合自己业务规则的告警传播器,设置在DataBox上使用。
这里,我们对前面创建的数据添加一些告警,代码被封装在step7函数中。
//还没看明白 private void step7() { //create and set a summing propagator to the data source, //here will make the box propagate alarms to its parent. box.setAlarmPropagator(new SummingAlarmPropagator()); //get a port in the equipment rack. Port nodeA = (Port) box.getElementByID("0:0"); AlarmState alarmState = nodeA.getAlarmState(); //add an acknowledged alarm with critical severity. alarmState.acknowledgeAlarm(AlarmSeverity.CRITICAL); //add and new alarm with major severity. alarmState.addNewAlarm(AlarmSeverity.MAJOR); //get another port. Port nodeB = (Port) box.getElementByID("3:3"); alarmState = nodeB.getAlarmState(); //add 10 new alarms with critical minor. alarmState.increaseNewAlarm(AlarmSeverity.MINOR, 10); }
step8 添加装饰图标
TWaver支持在各种数据对象上附着显示一些动态图标,用来表示一些动态的网络事件信息。例如,一个设备出了告警之外,还有一些其他并不像告警那么严重的时间信息,这些信息也需要用一种非常直观、醒目的方式显示出来提示用户。这种情况下,可以使用Attachment附件机制。装饰图标就是一种附件,它用一个小图标来表示某些事件的发生,并显示在对应的宿主对象边缘,用于显示一些网络上发生的动态事件和信息。TWaver默认提供了一些预定义的装饰图标,可以直接使用。这些都被IconAttachmentHolder类进行统一管理。扩展新的装饰图标也很简单。我们通过代码进行演示如何操作。首先,我们需要一个小图标: icon,然后我们定义一个新的装饰图标并进行注册,然后让它显示在某一个Element上面。装饰图标从IconAttachment进行继承,我们重载构造函数,指定我们的图标即可。新的装饰图标需要是一个顶级类,我们推荐用public static来定义,或者放入单独的一个文件中TUIManager.registerAttachment方法进行注册,这样在运行过程中,就可以用element.addAttachment方法显示装饰图标了。
//define a new LayoutedIconAttachment. //It must define as public static class. public static class MyIconAttachment extends IconAttachment{ public MyIconAttachment(String name, ElementUI ui) { super(name, ui, TWaverUtil.getImageIcon("myIcon.png")); } } private void step8() { String iconName="document"; TUIManager.registerAttachment(iconName, MyIconAttachment.class); //put a "document" icon on element B. Element element = box.getElementByID("A"); element.addAttachment(iconName); }
step9 添加显示特效
TWaver提供了丰富的显示特效,尤其在拓扑图上面。例如,我们可以在连线上显示流动的特殊动画效果。我们通过对应的API函数就可以实现这种效果,非常简单。单击中间的Link会显示加粗
private void step9() { //get the link element. Link element = (Link)box.getElementByID("link"); //make the link animating flowing element.putLinkFlowing(true); //set the link flowing color element.putLinkFlowingColor(Color.black); //set the link outline color element.putLinkOutlineColor(Color.black); //set the link body color. element.putLinkColor(Color.white); //set the link lable font element.putLabelFont(new Font("Impact", 1, 20)); //set the link lable color element.putLabelColor(Color.MAGENTA); }
总的代码
import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import twaver.*; import twaver.network.*; import twaver.network.ui.*; import twaver.table.*; import twaver.tree.*; public class Tutorial extends JFrame { private TDataBox box = new TDataBox("Simple Data Box"); private TNetwork network; private TTree tree; private JPanel networkPane = new JPanel(new BorderLayout()); private JPanel treePane = new JPanel(new BorderLayout()); private JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePane, networkPane); public Tutorial() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); getContentPane().add(split, BorderLayout.CENTER); split.setDividerLocation(200); // 不加的话,左边的框显示不出来 doSample(); } public static void main(String[] args) { Tutorial frame = new Tutorial(); frame.setSize(500, 300); frame.setTitle("TWaver Tutorial"); TWaverUtil.centerWindow(frame); frame.setVisible(true); } private void doSample() { try { step1(); // step2(); // step3(); // step4(); // step5(); // step6(); // step7(); // step8(); // step9(); } catch (Exception ex) { ex.printStackTrace(); } } private void step1() { network = new TNetwork(box); // network.setToolbarByName(""); //这句话可以把工具栏去掉 networkPane.add(network, BorderLayout.CENTER); Node nodeA = new Node("A"); nodeA.setName("I'm node A!"); nodeA.setLocation(50, 50); box.addElement(nodeA); Node nodeB = new Node("B"); nodeB.setName("I'm node B!"); nodeB.setLocation(200, 200); box.addElement(nodeB); Link link = new Link("link", nodeA, nodeB); link.setName("Telephone Line"); box.addElement(link); } private void step2() { Dummy nodeDummy = new Dummy("node dummy"); nodeDummy.setName("All Nodes"); nodeDummy.addChild(box.getElementByID("A")); nodeDummy.addChild(box.getElementByID("B")); box.addElement(nodeDummy); Dummy linkDummy = new Dummy("link dummy"); linkDummy.setName("All Links"); linkDummy.addChild(box.getElementByID("link")); box.addElement(linkDummy); // 只是用来分类,不加这两个Dummy会把Node和Link放到一块 tree = new TTree(box); JScrollPane scroll = new JScrollPane(tree); treePane.add(scroll, BorderLayout.CENTER); // 这里要套一个scrollpane,nodepane没套是因为TNetwork已经有了 } private void step3() { // add chassis to node A. Node node = (Node) box.getElementByID("A"); Chassis chassis = new Chassis("Chassis A"); chassis.setDataSource("/equipment1_template.xml"); node.addChild(chassis); box.addElement(chassis); } private void step4() { //Create a popup menu generator PopupMenuGenerator popupMenuGenerator = new PopupMenuGenerator() { /** * Add the identifier of each of the selected objects to the menu. * In this example, the items added to the menu do nothing. * In a real application, you would probably associate an * implementation of the Swing Action interface with each menu item. */ public JPopupMenu generate(TView tview, MouseEvent mouseEvent){ //Create an empty pop-up menu. JPopupMenu popMenu = new JPopupMenu(); JMenuItem item; //If the selectedObjects collection is empty, no objects are selected. if (tview.getDataBox().getSelectionModel().isEmpty()) { popMenu.add("Nothing selected"); } else { //Access the selected objects from the selection model. Iterator it = tview.getDataBox().getSelectionModel().selection(); while (it.hasNext()) { Element element = (Element) it.next(); popMenu.add(element.getName()); } } //If menu is empty, return null. if (popMenu.getComponentCount() == 0) { return null; } else { return popMenu; } } }; //Set the pop-up menu generator for network components network.setPopupMenuGenerator(popupMenuGenerator); } private void step5() { network.getCanvas().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { //获取双击的网元对象 Element element = network.getElementPhysicalAt(e.getPoint()); String message; if (element == null) { message = "You clicked nothing."; } else { message = "You clicked '" + element.getName() + "'"; } JOptionPane.showMessageDialog(network, message); } } }); } private void step6() { //create a selection listener. DataBoxSelectionListener listener = new DataBoxSelectionListener() { public void selectionChanged(DataBoxSelectionEvent e) { //get the last selected element and make it visible. Element element = e.getBoxSelectionModel().lastElement(); if (element != null) { network.ensureVisible(element); } } }; box.getSelectionModel().addDataBoxSelectionListener (listener); } private void step7() { //create and set a summing propagator to the data source, //here will make the box propagate alarms to its parent. box.setAlarmPropagator(new SummingAlarmPropagator()); //get a port in the equipment rack. Port nodeA = (Port) box.getElementByID("0:0"); AlarmState alarmState = nodeA.getAlarmState(); //add an acknowledged alarm with critical severity. alarmState.acknowledgeAlarm(AlarmSeverity.CRITICAL); //add and new alarm with major severity. alarmState.addNewAlarm(AlarmSeverity.MAJOR); //get another port. Port nodeB = (Port) box.getElementByID("3:3"); alarmState = nodeB.getAlarmState(); //add 10 new alarms with critical minor. alarmState.increaseNewAlarm(AlarmSeverity.MINOR, 10); } //define a new LayoutedIconAttachment. //It must define as public static class. public static class MyIconAttachment extends IconAttachment{ public MyIconAttachment(String name, ElementUI ui) { super(name, ui, TWaverUtil.getImageIcon("myIcon.png")); } } private void step8() { String iconName="document"; TUIManager.registerAttachment(iconName, MyIconAttachment.class); //put a "document" icon on element B. Element element = box.getElementByID("A"); element.addAttachment(iconName); } private void step9() { //get the link element. Link element = (Link)box.getElementByID("link"); //make the link animating flowing element.putLinkFlowing(true); //set the link flowing color element.putLinkFlowingColor(Color.black); //set the link outline color element.putLinkOutlineColor(Color.black); //set the link body color. element.putLinkColor(Color.white); //set the link lable font element.putLabelFont(new Font("Impact", 1, 20)); //set the link lable color element.putLabelColor(Color.MAGENTA); } }
相关文章推荐
- 【模板】SPFA Dijkstra+Heap(priority_queue)
- Queue 应用——拓扑排序
- 响应式web设计之CSS3 Media Queries
- hdu 1005 Number Sequence
- 记忆化搜索 Codeforces666A Reberland Linguistics
- 设计模式(三)建造者模式Builder(创建型)
- 设计模式(三)建造者模式Builder(创建型)
- 笔记2:WebRequest 及 WebResponse 类介绍
- PipelineDraweeControllerBuilder.obtainController()源码分析
- HDU 3836 Equivalent Sets 强连通分量分解
- Codeforces 667C Reberland Linguistics 记忆化搜索
- 告诉你TestNG annotations注释都是什么时候运行的
- Easui中datagrid实现动态控制columns
- hdu4027 Can you answer these queries?(成段更新)
- Errors while building APK. You can find the errors in the 'Messages' view.
- org.hibernate.exception.JDBCConnectionException: could not execute queryMySQL数据库连接超时
- Codeforces Round #349 (Div. 1) A. Reberland Linguistics 动态规划
- 海量数据存储之Key-Value存储简介
- 海量数据存储之Key-Value存储简介
- 大数据时代的 9 大Key-Value存储数据库