本节教程在第二节的基础上继续完善工作流流程设计器,本节的主要内容有:
通过GMF向导生成的节点都是矩形,为了使图形更加美观、更好的用户UI,我们需要自定义图形节点。下面以开始和结束活的为例,介绍如何使用自定义图标。
a) 选择Canvas Gallery Default->Figure Descriptor StartActivityFigure,将子节点Retangle StartActivityFigure删除,右键点击Figure Descriptor StartActivityFigure,New Child->Custom Figure, 输入名称StartActivityFigure, 在Qualified Class Name填写自定义的类名,这个类一般继承org.eclipse.draw2d.Figure,在这里填写类 名:com.mjt.flow.diagram.figure.StartActivityFigure,按照同样方法,在 EndActivityFigure新建Custom Figure;建立完毕后如下图:
b)开始和结束活动使用图片大小固定,在这里我们把它改成不可变大小,设置Node StartActivity和Node EndActivity的Resize Constraint为NONE,如下图:
c)在图形文件flow.gmfgraph定义了自定义类,现在需要建立这个两个类,首先新建开始活动Figure类,该类继承org.eclipse.draw2d.Figure这个类,如下:
- 自定义节点图标
- 自定义形状
1.自定义节点图标
通过GMF向导生成的节点都是矩形,为了使图形更加美观、更好的用户UI,我们需要自定义图形节点。下面以开始和结束活的为例,介绍如何使用自定义图标。
- 我们继续在第二节基础上,打开com.mjt.flow.diagram项目,在icons新建文件夹custom,将之前准备好的的图标放入该目录,这里使用的是start.png和end.png,图片大小32*32。
- 由于需要使用自定义图标,所以需要在flow.gmfgraph文件进行图形设置,需要将形状设置成自定义形状。
a) 选择Canvas Gallery Default->Figure Descriptor StartActivityFigure,将子节点Retangle StartActivityFigure删除,右键点击Figure Descriptor StartActivityFigure,New Child->Custom Figure, 输入名称StartActivityFigure, 在Qualified Class Name填写自定义的类名,这个类一般继承org.eclipse.draw2d.Figure,在这里填写类 名:com.mjt.flow.diagram.figure.StartActivityFigure,按照同样方法,在 EndActivityFigure新建Custom Figure;建立完毕后如下图:
b)开始和结束活动使用图片大小固定,在这里我们把它改成不可变大小,设置Node StartActivity和Node EndActivity的Resize Constraint为NONE,如下图:
c)在图形文件flow.gmfgraph定义了自定义类,现在需要建立这个两个类,首先新建开始活动Figure类,该类继承org.eclipse.draw2d.Figure这个类,如下:
d)类向导建立com.mjt.flow.diagram.figure.StartActivityFigure这个类后,这个类是个空白的类,什么都没有,现在我们覆盖基类的paintFigure(Graphics graphics)方法,输入以下代码:
package com.mjt.flow.diagram.figure; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.Graphics; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.Image; import com.mjt.flow.diagram.part.FlowDiagramEditorPlugin; public class StartActivityFigure extends Figure { @Override protected void paintFigure(Graphics graphics) { setFigureImage(graphics, "icons/custom/start.png",32,3); //$NON-NLS-1$ } protected void setFigureImage(Graphics graphics, String imagePath, int width, int height){ super.paintFigure(graphics); ImageDescriptor descriptor = FlowDiagramEditorPlugin.findImageDescriptor(imagePath); Image image = descriptor.createImage();//创建图形 graphics.drawImage(image, getLocation());//绘制图标 setPreferredSize(width, height); //设置首选(默认)大小 } } |
e)同时还需要设设置NodeFigure的DefaultSize,打开 com.mjt.flow.diagram.edit.parts.StartActivityEditPart这个类,在 createNodePlate()方法中新建DefaultSizeNodeFigure类时,需要设置DefaultSize为26、26,同时不要 忘记设置EndtActivityEditPart类,如下:
Tip:@generated NOT标注可以当GMF重新生成代码的时候不会被覆盖,不会重新生成。
f)gmfgrap文件改动过了,需要重新生成flow.gmfgen文件,删除flow.gmfgen文件,右键点击 flow.gmfmap文件,Create Generator Model...,点击Generate Diagram Code...,重新生成diagram code。
g)运行一下如下图:
h)细心的您是否发现,当在画开始和结束活动时,如果拖动的比较大时,此时图形有不能调整大小,怎么办呢?这时需要您添加另外的代码控制图形大小。
此 时需要覆盖com.mjt.flow.diagram.edit.parts.StartActivityEditPart中的 handleNotificationEvent(Notification notification)方法,在这里进行控制图形的大小,如下:
/** * @generated NOT */ protected NodeFigure createNodePlate() { DefaultSizeNodeFigure result = new DefaultSizeNodeFigure(26,26); return result; } |
f)gmfgrap文件改动过了,需要重新生成flow.gmfgen文件,删除flow.gmfgen文件,右键点击 flow.gmfmap文件,Create Generator Model...,点击Generate Diagram Code...,重新生成diagram code。
g)运行一下如下图:
h)细心的您是否发现,当在画开始和结束活动时,如果拖动的比较大时,此时图形有不能调整大小,怎么办呢?这时需要您添加另外的代码控制图形大小。
此 时需要覆盖com.mjt.flow.diagram.edit.parts.StartActivityEditPart中的 handleNotificationEvent(Notification notification)方法,在这里进行控制图形的大小,如下:
/** * 创建图形时自动适应PreferredSize大小。 * @generated NOT */ @Override protected void handleNotificationEvent(Notification notification) { setToPreferredSize(notification, getFigure(), (View) getModel(), getEditingDomain(), getDiagramEditDomain()); super.handleNotificationEvent(notification); } /** * Resize Constraint属性值改为NONE时,创建图形拖动时大小如果大于PreferredSize时, * 不会将图形适合到PreferredSize大小, 此方法为了解决这个问题 * @generated NOT */ public static void setToPreferredSize(Notification notification, IFigure figure, View model, TransactionalEditingDomain editingDomain, IDiagramEditDomain diagramEditDomain){ if(notification.getEventType()==Notification.SET && !figure.getSize().equals(figure.getPreferredSize())){ SetBoundsCommand boundsCommand = new SetBoundsCommand(editingDomain,"", //$NON-NLS-1$ new EObjectAdapter(model),figure.getPreferredSize()); diagramEditDomain.getDiagramCommandStack().execute(new ICommandProxy(boundsCommand)); } } |
i)再仔细看一下下面的图形,有没有发现,当连接线成斜线的时候,由于里面的图形是圆形而外框是矩形,默认情况下,连接线的锚点是矩形的。如下:
如 何自定义锚点呢?这时候需要覆盖 com.supcon.workflow.xpdl.diagram.edit.parts.StartActivityEditPart#getSourceConnectionAnchor 和#getTargetConnectionAnchor方法,如下:
/** * @generated NOT */ @Override public ConnectionAnchor getSourceConnectionAnchor( ConnectionEditPart connEditPart) { return new EllipseAnchor(getFigure()); } /** * @generated NOT */ @Override public ConnectionAnchor getSourceConnectionAnchor(Request request) { return new EllipseAnchor(getFigure()); } /** * @generated NOT */ @Override public ConnectionAnchor getTargetConnectionAnchor( ConnectionEditPart connEditPart) { return new EllipseAnchor(getFigure()); } /** * @generated NOT */ @Override public ConnectionAnchor getTargetConnectionAnchor(Request request) { return new EllipseAnchor(getFigure()); } |
draw2d 为我们提供很多默认的Anchor,这里使用的是椭圆的Anchor,实现的Anchor除了EllipseAnchor还有 DiamondConnectionAnchor、ChopboxAnchor、SlidableAnchor等,有兴趣的话可以自己去研究一下,同时可 以自定义Anchor,只要继承抽象类org.eclipse.draw2d.AbstractConnectionAnchor来完成自定义的 ConnectionAnchor。
再看一下运行结果:
2.自定义形状
这一块内容我们将以AutoActivity活动为例,对其进行自定义形状,采用渐变填充。a)首先按照自定义节点图标的方法,在flow.gmfgraph新建Custom Figure, 由于原来有子节点GridLayout和Label, 删除后重新加上去,如下图:
b) 新建自定义形状类com.mjt.flow.diagram.figure.AutoActivityFigure, 继承org.eclipse.draw2d.Shape,由于Shape是抽象类,需要实现两个方法fillShape(Graphics graphics)和outlineShape(Graphics graphics),前面主要用于图形填充,后者用于形状外边框。
类代码如下:
package com.mjt.flow.diagram.figure; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.Shape; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Path; import org.eclipse.swt.graphics.RGB; /** * 自动活动自定义Figure */ public class AutoActivityFigure extends Shape { protected Dimension corner = new Dimension(20, 20); @Override protected void fillShape(Graphics graphics) { //通过路径绘制圆角矩形 Path path = new Path(null); path.addArc(getBounds().x, getBounds().y, corner.width, corner.height, 180, -90); path.addArc(getBounds().x+getBounds().width-corner.width, getBounds().y, corner.width, corner.height, 90,-90); path.addArc(getBounds().x+getBounds().width-corner.width, getBounds().y+getBounds().height-corner.height, corner.width, corner.height, 0,-90); path.addArc(getBounds().x, getBounds().y+getBounds().height-corner.height, corner.width, corner.height, 270,-90); graphics.setClip(path); //渐变填充 graphics.setForegroundColor(ColorConstants.white); graphics.setBackgroundColor(new Color(null, new RGB(200,220,230))); graphics.fillGradient(getBounds(), true); } @Override protected void outlineShape(Graphics graphics) { float lineInset = Math.max(1.0f, getLineWidthFloat()) / 2.0f; int inset1 = (int) Math.floor(lineInset); int inset2 = (int) Math.ceil(lineInset); Rectangle r = Rectangle.SINGLETON.setBounds(getBounds()); r.x += inset1; r.y += inset1; r.width -= inset1 + inset2; r.height -= inset1 + inset2; graphics.setForegroundColor(new Color(null, new RGB(40,100,120))); graphics.drawRoundRectangle(r, Math.max(0, corner.width - (int) lineInset), Math .max(0, corner.height - (int) lineInset)); } } |
c)重新生成flow.gmfgen文件,并重新生成diagram代码。
d)运行结果如下:
源代码请看附件
这一节讲完了,下一节的内容是如何扩展流程的自定义字段。
由于平时比较忙,可能写的比较简单,有些地方没有详细说明,一笔带过,如果有什么不明白之处,欢迎通过邮件联系。
本系列教程尽量会在最短的时间内写出来。