Posted on 2010-11-24 09:49
TWaver 阅读(3556)
评论(1) 编辑 收藏
linkUML图大家都看过,可能大家也比较熟悉,有时候也希望能通过UML图形的方式展示一些网管业务逻辑,比如以下逻辑

下面通过一系列的功能点讲解,教大家如何使用TWaver实现UML效果,最终效果图如下

Step1, 如何实现UML图形的节点,效果如下:

功能点介绍
Step1.1 如何实现文字换行居中
TWaver中网元的Label默认就已经提供了对于html的支持,所以可以通过如下代码实现文字换行居中效果
1
node.putLabelPosition(TWaverConst.POSITION_CENTER);
2
node.setDisplayName("<html><center>网络资源<br>(Resource)</center></html>");
Step1.2 如何让网元显示成UML流程节点形状
这个主要有两个功能点
a:平时开发过程中,一般的网元都显示成图标的形式以代表业务逻辑,其实TWaver默认提供了一组CustomDraw的图形,可以将网元显示成不同的形状,如下图所示:

通过设置CustomDraw的属性就可以达到矩形的效果
Step1.3 如何在节点下面绘制几条分割线,这个功能很好的体现了TWaver中MVC的架构,对Swing熟悉一些的开发人员都知道,像JButton,JTextField等Swing组件都会有一些对应的UI类,比如ButtonUI,TextFieldUI进行绘制,开发人员可以很方便的通过LookAndFeel切换UI进行换肤操作。TWaver中网元渲染原理类似,像Node,Link都有对应的UI,NodeUI、LinkUI进行渲染,通过很方便的重载这些UI实现效果定制,比如TWaveDemo中的Custom Link Demo和Instrument Demo,如下图所示

UMLNode的实现也类似,首先定义了一个UMLNode类,在里面设置了一些列的CustomDraw属性(参考Step1.2),然后继承ResizableNodeUI实现了一个UMLNodeUI,在里面绘制了几条分割线,代码如下
1
public class UmlNode extends ResizableNode
{
2
3
public UmlNode()
{
4
super();
5
initNode();
6
}
7
8
public UmlNode(Object id)
{
9
super(id);
10
initNode();
11
}
12
13
private void initNode()
{
14
this.putCustomDraw(true);
15
this.putCustomDrawGradient(true);
16
this.putCustomDrawGradientFactory(TWaverConst.GRADIENT_LINE_N);
17
this.putCustomDrawFillColor(new Color(255, 200, 100, 150));
18
this.putCustomDrawShapeFactory(TWaverConst.SHAPE_RECTANGLE);
19
this.putCustomDrawOutlineColor(new Color(200, 0, 200));
20
21
this.putLabelPosition(TWaverConst.POSITION_CENTER);
22
this.putLabelFont(TUIManager.getDefaultPlainFont());
23
this.setSize(220, 60);
24
}
25
26
//重载UI
27
public String getUIClassID()
{
28
return UmlNodeUI.class.getName();
29
}
30
31
}
32
33
public class UmlNodeUI extends ResizableNodeUI
{
34
35
public UmlNodeUI(TNetwork network, ResizableNode node)
{
36
super(network, node);
37
}
38
39
//想怎么画就怎么画
40
protected void paintCustomDraw(Graphics2D g2d)
{
41
super.paintCustomDraw(g2d);
42
Rectangle bounds = this.getUIBounds();
43
44
g2d.drawLine(bounds.x+2, bounds.y+bounds.height-6, bounds.x+bounds.width-2, bounds.y+bounds.height-6);
45
g2d.drawLine(bounds.x+2, bounds.y+bounds.height-12, bounds.x+bounds.width-2, bounds.y+bounds.height-12);
46
}
47
}
通过以上处理,就可以达到UML节点的效果了
Step2,如何实现UML的折线子环效果
TWaver中的Link默认有自环环效果,效果如下

但这个显然不是我们想要的,因为它默认只有圆形效果,这个时候我们就想到了另外一种Link,ShapeLink,顾名思义,这个Link是由一个Shape形状来表示的,那么我们能不能通过ShapeLink来实现折线子环的效果呢,答案是肯定的,只需要小小的定制即可,代码如下
1
public class LoopLink extends ShapeLink
{
2
3
public LoopLink(Node node)
{
4
super();
5
initLink();
6
}
7
8
public LoopLink(Object id, Node node)
{
9
super(id);
10
this.setFrom(node);
11
this.setTo(node);
12
initLink();
13
}
14
15
private double wExtend = 0.5;
16
private double hExtend = 0.5;
17
18
private void initLink()
{
19
this.putLinkFromPosition(TWaverConst.POSITION_RIGHT);
20
this.putLinkToPosition(TWaverConst.POSITION_BOTTOM);
21
this.setLinkType(TWaverConst.LINK_TYPE_YSPLIT);
22
this.putLinkOutlineWidth(0);
23
this.putLinkWidth(1);
24
this.putRenderColor(Color.BLUE);
25
this.putLinkToArrow(true);
26
this.putLinkToArrowStyle(TWaverConst.ARROW_DELTA_GREAT);
27
this.putLinkToArrowOutlineColor(Color.RED);
28
this.putLinkToArrowColor(Color.WHITE);
29
30
Node node = this.getFrom();
31
//注意此处,因为默认ShapeLink上的点是不会跟随Node移动的,所以为了实现跟随效果,这里通过监听Node的属性变化进行了更新处理
32
node.addPropertyChangeListener(new PropertyChangeListener()
{
33
public void propertyChange(PropertyChangeEvent evt)
{
34
if (TWaverConst.PROPERTYNAME_LOCATION.equals(evt.getPropertyName()))
{
35
validatePoints();
36
}
37
}
38
});
39
validatePoints();
40
}
41
42
private void validatePoints()
{
43
this.clear();
44
Node node = this.getFrom();
45
Rectangle bounds = node.getBounds();
46
Point2D p1 = new Point2D.Double(bounds.getCenterX() + bounds.getWidth() / 2, bounds.getCenterY());
47
this.addPoint(p1);
48
Point2D p2 = new Point2D.Double(bounds.getCenterX() + bounds.getWidth() / 2 + bounds.getWidth() * wExtend, bounds.getCenterY());
49
this.addPoint(p2);
50
Point2D p3 = new Point2D.Double(bounds.getCenterX() + bounds.getWidth() / 2 + bounds.getWidth() * wExtend, bounds.getCenterY() + bounds.getHeight() / 2
51
+ bounds.getHeight() * hExtend);
52
this.addPoint(p3);
53
Point2D p4 = new Point2D.Double(bounds.getCenterX(), bounds.getCenterY() + bounds.getHeight() / 2 + bounds.getHeight() * hExtend);
54
this.addPoint(p4);
55
}
56
57
}
通过这样就可以达到折线自环的效果了,效果图如下

Step3 如何实现Link折线效果和From/To端文字标注
Step 3.1 如何实现Link折线效果,其实这个很简单,不过可能大多数人都会忽略TWaver默认提供的这个功能,通过设置不同的LinkType,Link可以显示成各种样式,如下图所示

通过如下代码即可达到UML图中的连线效果
1
private void initLink()
{
2
this.setLinkType(TWaverConst.LINK_TYPE_YSPLIT);
3
this.putLinkOutlineWidth(0);
4
this.putLinkWidth(1);
5
this.putRenderColor(Color.BLUE);
6
this.putLinkToArrow(true);
7
this.putLinkToArrowStyle(TWaverConst.ARROW_DELTA_GREAT);
8
this.putLinkToArrowOutlineColor(Color.RED);
9
this.putLinkToArrowColor(Color.WHITE);
10
}
Step3.2 如何在Link的From/To端进行标注
效果如下

实现原理:这个借助了TWaver中Attachment的概念,顾名思义,Attachment即附件,它的主要功能就是附加一些信息到网元上,Attachment有很多种,简单点的可以显示一串文字,复杂点的可以显示一些组件在界面上,想TWaverDemo的AttachmentDemo,如下图所示

文字标注也可以通过这种方式进行处理,TWaver内部对于Link的From和To两个位置都有对应的定义
1
TWaverConst.POSITION_LINK_FROM_ANCHOR
2
TWaverConst.POSITION_LINK_TO_ANCHOR
既然有了这个实现起来就很简单了,我们只需要自定义一个Label的Attachment,然后将其放到From或To的Postion既可以了,见如下代码
1
public class LinkLabelAttachment extends ComponentAttachment
{
2
3
public final static String LINKFROMLABEL = "linklabelattachment.linkfromlabel";
4
5
public LinkLabelAttachment(String name, ElementUI ui)
{
6
super(name, ui);
7
initLabel();
8
}
9
10
public LinkLabelAttachment(String name, ElementUI ui, boolean minimized, boolean shrinked)
{
11
super(name, ui, minimized, shrinked);
12
initLabel();
13
}
14
15
private JLabel label = new JLabel()
{
16
{
17
this.setHorizontalAlignment(SwingConstants.CENTER);
18
this.setDoubleBuffered(false);
19
}
20
};
21
22
private void initLabel()
{
23
label.setFont(LinkLabelDemo.USECUSTOMERFONT);
24
label.setForeground(LinkLabelDemo.LABELCOLOR);
25
26
setLabelText();
27
this.setPosition(TWaverConst.POSITION_LINK_FROM_ANCHOR);
28
this.setComponent(label);
29
}
30
31
private void setLabelText()
{
32
Object obj = element.getClientProperty(LINKFROMLABEL);
33
if (obj != null)
{
34
label.setText(obj.toString());
35
}
36
else
{
37
label.setText("");
38
}
39
//可以调整此参数设置文字的偏移
40
this.setXOffset(30);
41
this.setWidth(label.getPreferredSize().width + 2);
42
this.setHeight(label.getPreferredSize().height + 2);
43
}
44
45
public void elementPropertyChange(PropertyChangeEvent evt)
{
46
super.elementPropertyChange(evt);
47
if (LINKFROMLABEL.equals(TWaverUtil.getPropertyName(evt)))
{
48
setLabelText();
49
}
50
}
51
52
}
Link添加以上Attachment以后就会自动出现在Link的from端
至于另外一端的标签,我们可以通过TWaver内置的一个Attachment,即Message来实现,代码如下
1
public void setToLabel(String label)
{
2
this.putMessageContent(label);
3
if (!this.containsAttachment(TWaverConst.ATTACHMENT_MESSAGE))
{
4
this.addAttachment(TWaverConst.ATTACHMENT_MESSAGE);
5
this.putMessageStyle(TWaverConst.MESSAGE_COMPONENT_LABEL);
6
this.putMessageBorderVisible(false);
7
this.putMessageOpaque(false);
8
this.putMessagePosition(TWaverConst.POSITION_LINK_TO_ANCHOR);
9
this.putMessageShadowVisible(false);
10
this.putMessageFont(LinkLabelDemo.USECUSTOMERFONT);
11
this.putMessageForeground(LinkLabelDemo.LABELCOLOR);
12
JLabel label2 = new JLabel();
13
label2.setText(this.getMessageContent());
14
label2.setFont(LinkLabelDemo.USECUSTOMERFONT);
15
//可以设置以下参数设置Message的偏移
16
this.putMessageXOffset(30);
17
}
18
}
通过以上代码就可以实现在Link两端添加标签的效果了
源码请到此处下载:twaver.servasoft.com