SWT/JFace学习总结
一. SWT/JFace的基本介绍
1.1 Face与其他图形界面设计工具的比较
Java图形界面实现方式有很多,比如AWT、SWING和SWT等。AWT和SWING不论是在速度上还是美观上都有很大的不足;对于比较庞大而复杂的系统,用AWT或SWING相很难实现,因为运行的速度会相当的慢。SWT直接使用操作系统提供的本地图形接口,具备本地化的Look & Feel,效率高且美观。因此,本项目选择SWT作为图形界面开发基础工具包。
图2-1为SWT原理图,图2-2为JFace原理图
图2-1 |
|
SWT把Win32的API简单的包装了一下,系统在SWT这一层调用的方法、传递的参数被原封不动的代理到了Win32层。这是SWT的核心思想。SWT有一个很重要的设计原则,那就是,SWT的API一对一的封装OS的API,完全忠实于操作系统的API实现的行为,如果有bug,那也是OS的bug,它不会尝试去“纠正”操作系统,因为那样会潜在的破坏本地化的一些行为。忠实于OS也使得调用者不必但心自己的SWT程序会跟OS的本地GUI有不一致的地方。因此,SWT拥有标准的与操作系统相同的外观,几乎没有人能看出你的程序是用Java写出来的,更为重要的是,其程序运行的效率可以和VC++写出的程序向媲美,而且开发的效率也不在AWT/SWING之下。
1.2 如何创建简单的SWT/JFace程序
1.2.1 如何在Eclipse中建立一个SWT/JFace工程
依次File→New→other 就会看到
然后按向导往下操作即可新建一个SWT/JFace工程,该工程跟其他的Jave工程没有多大的区别
1.2.2 一个简单的HelloWorld小例子
public class HelloWorld{ public static void main(String[] args){ Display display=new Display(); Shell shell=new Shell(display,SWT.V_SCROLL|SWT.SHELL_TRIM);
shell.setText("This is my label"); shell.setBounds(100,100,500,200); shell.setLayout(new FillLayout());
//Color red=new Color(display,255,0,0);
Label label1=new Label(shell,SWT.CENTER); label1.setText("Hello word"); label1.setLocation(100,100); label1.setBackground(new Color(display,0,200,0)); new Label(shell,SWT.CENTER).setText("software college of neu");
shell.open(); while(!shell.isDisposed()){ if(!display.readAndDispatch()) display.sleep(); } display.dispose();
} } |
程序的一些解释:
1. Display类:该类是SWT的基础类,它负责应用程序和本地操作系统之间建立交互。Display类是从Decive继承而来。
Display继承关系图
2. Shell类:该类是显示在桌面上的窗口,可以使顶级窗口(Top Level Shells)或者是对话框窗口(Secondary Or Dialog Shells)
3. 设置消息循环进行监听,以便监听到界面的操作:
while(!shell.isDisposed()){ if(!display.readAndDispatch()) display.sleep(); }
|
二. SWT基础
2.1 SWT基本组件
2.1.1关于按钮Button
类型 | 特点 | 创建代码举例 |
普通 | 呈突出状 | Button bt = new Button(shell,SWT.PUSH) |
切换 | 单击后保持按下状态,再次单击时恢复。 | Button bt = new Button(shell,SWT.TOGGLE) |
箭头 | 按钮带有小箭头 | Button bt = new Button(shell , SWT.ARROW|SWT.UP)向上的箭头 |
单选 | 同一组只有一个选中 | Group group = new Group(shell , SWT.SHADOW_ETCHED_OUT) group.setLayout(new FillLayout(SWT.VERTICAL) Button bt1 = new Button(group , SWT.RADIO|SWT.LEFT) Button bt2 = new Button(group, SWT.RADIO|SWT.RIGHT)
bt1.setSelection(true)表示选定该按钮 |
多选 | 同时可选几个按钮 | Group group = new Group(shell , SWT.SHADOW_ETCHED_OUT) group.setLayout(new FillLayout(SWT.VERTICAL) Button bt1 = new Button(group , SWT.CHECK|SWT.LEFT) Button bt2 = newButton(group, SWT.CHECK|SWT.RIGHT)
bt1.setSelection(true)表示选定该按钮 |
2.1.2文本框Text
文本框是一个比较常用的组件,文本狂本身就支持复制,粘贴,删除等基本的操作。因此这些常用的基本操作不用我们再去设计。
1.文本框的比较特殊的样式
样式常量 | 描述 |
SWT.READ_ONLY | 只读文本框 |
SWT.PASSWORD | 输入密码框 |
SWT.MULTI | 可以输入多行的文本框 |
SWT.WRAP | 可以输入多行并且自动切换 |
SWT.H_SCROLL | 带水平滚动条的文本框 |
2.关于文本框的几个操作的方法
设置文字的方向 | setOrientation(int orientation) | SWT.RIGHT_TO_LEFT 则从右往左填充 |
设置文本输入字符的格式 | setEchoChar(char echo) | Example:setEchoChar(“*”),输入时则显示“*” |
设置Tab退格的字符数 | setTabs(int tabs) | tabs是多大就退几格 |
全选 | selectAll() |
|
取消所有选择 | clearSelection() |
|
将所选的字符复制到剪贴板 | copy() |
|
将所选的字符剪切到剪贴板 | cut() |
|
将剪贴板上的字符粘贴到文本框 | paste() |
|
2.2面板容器类
2.2.1 自定义选项卡CTabFolder
自定义选项卡比TabFolder类的功能强大,我们可以给他添加一些最大化最小化的按钮,可以做出仿eclipse编辑区的选项卡;
①. 带有关闭的选项卡;初始化时将风格设置为SWT.CLOSE即可;
CTabFolder tabFolder = new CTabFolder(shell,SWT.CLOSE);
②. 带有最大化最小化按钮
tabFolder.setMaxmizeVisible(true);//显示最大化按钮
tabFolder.setMininizeVisible(true);//显示最小化按钮 |
③. 设置选项卡(选中状态标签)的背景和颜色
l 单一的前景色和背景色
tabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_WHITE));
tabFolder.setSelectionBackground(display.getSystemColor(SWT.COLOR_BLUE)); |
l 渐变的背景色
设置渐变背景的方法是setSelectionBackground(Color[] color, int[] percents)或setSelectionBackground(Color[] color, int[] percents, Boolean vertical),第二个方法的vertical表示是否垂直渐变;
Color[] color = new Color[4]; color[0] = display.getSystemColor(SWT.COLOR_DARK_BLUE); color[1] = display.getSystemColor(SWT.COLOR_BLUE); color[2] = display.getSystemColor(SWT.COLOR_WHITE); color[3] = display.getSystemColor(SWT.COLOR_WHITE); int[] intArray = new int[]{25, 50, 100}; tabFolder.setSelectionBackground(color,intArray); |
l 设置背景图片,setSelectionBackground(Image image);
④. 最大化最小化按钮的监听;
添加监听的语句是
tabFolder.addCTabFolder2Listener(new CTabFolder2Adapter(){});
设置最大化,最小化和还原,实现以下方法
public void mimimize(CTabFolderEvent e){}
public void maximize(CTabFolderEvent e){}
public void restore(CTabFolderEvent e){}
以下是最下化方法的代码
tabFolder.setMinimized(true);//设置选项卡为最小化,决定了右上角的按钮 tabFolder.setLayoutData(new GridData(SWT.FILL, SET.FILL, true, false));//改变布局,呈现最小化状态 shell.layout(true);//刷新布局,否则新的布局不能呈现出来 |
⑤. CTabFolder还有许多有用的方法,以上说的基本上可以构建出仿eclipse的选项卡了
2.2.2 滚动面板ScrolledComposite
对于滚动面板ScrolledComposite,看起来好像很好用,如果对于布局确定的面板来说,实现滚动效果确实比较简单,但对于一个没有确定布局的面板(比如一个可以往上面随意家图形的画布),那实现起来就要费一些心思。这里我们要实现一个没有确定布局的,可以随意添加图形的而且要求可以无限变大的面板。
l 首先,我们新建一个ScrolledComposite sc,然后将我们的画布canvas设为ScrolldeComposite的内容sc.setContent(canvas);为了让滚动条显示出来,我们可以canvas设置一个适当的大小
l 接下来最关键的是如何改变面板的大小,在改变大小之前,我们首先要判断出面板是否到了边界,因为这时才需要使面板的大小增大
(sc.getVerticalBar().getSize().y+sc.getVerticalBar().getSelection())
==sc.getVerticalBar().getMaximum())
如果等式成立就说明面板已经到了边界
l 这时只要在监听里重新设置面板的大小就可以了
2.2.3分割窗框SashForm
关于分割框的基本知识这里就不再介绍了,在这里主要讲述使用分割框和选项卡实现最大化和还原,其实这也很简单,只要用了setMaximizedControl(Control control)这个方法就可以了。
在我们点击选项卡的最大化时:
在点击还原是只要form.setMaximizedControl(null);整个面板就会还原到初始的比例
2.3 SWT布局管理器
三 SWT/JFace高级应用
3.1菜单和工具栏
l 菜单栏
在程序中,菜单是提供信息比较好的方式,SWT中通过Menu和MenuItem实现菜单和菜单项,在程序中添加菜单步骤如下:
u 创建Menu对象,并指定创建风格,menuBar = new Menu(shell,SWT.BAR);
u 一般的,我们不在菜单栏上直接创建Item,而是先创建一个新的Menu,然后再这个Menu上添加MenuItem;
u 创建MenuItem对象,并指定创建风格;
u 设置Menu和MenuItem的关联,例如”fileMenuHeader.setMenu(fileMenu)”;
u 添加MenuItem的事件监听器,
menuBar=new Menu(shell,SWT.BAR); fileMenuHeader=new MenuItem(menuBar,SWT.CASCADE); fileMenuHeader.setText("文件(&F)"); fileMenu=new Menu(shell,SWT.DROP_DOWN); fileMenuHeader.setMenu(fileMenu); fileNewItem=new MenuItem(fileMenu,SWT.PUSH); fileNewItem.setText("新建(&N)..."); shell.setMenuBar(menuBar); |
以上是在shell上添加菜单栏,并为菜单栏添加了一个菜单项的例子,有时我们要给一个面板添加一个右键弹出的菜单,下面是以canvas为例的一个简单的程序;
Menu menu = new Menu(canvas); MenuItem menuItem = new MenuItem(menu,SWT.PUSH); menuItem.setText("删除"); canvas.setMenu(menu); |
l 工具栏
工具栏为用户提供一些常用的菜单项作为它的按扭,方便用户操作。通常工具栏的建立语句如下(与菜单的添加相类似):
u 建立工具栏对象,指定风格;
u 创建ToolItem对象,指定风格;
u 设置关联
u 添加监听器
ToolBar toolbar = new ToolBar(shell, SWT.FLAT); ToolItem newItem = new ToolItem(toolBar,SWT.PUSH); //新建了一个ToolItem newItem.setImage(new Image(newItem.getDisplay(),"images//new.gif")); //为这个ToolItem 设置一个图标 newItem.setToolTipText("新建");//设置鼠标放在Item上时提示的语句; newItem.addSelectionListener(new MenuItemListener(shell)); //添加监听事件,MenuItemListener(shell)应该是继承 SelectionAdapter或者是SelectionListener的; new ToolItem(toolBar,SWT.SEPARATOR);//建立一个分隔符; |
3.2对话框
对话框是一个图形界面和用户交流的主要方式;对话框的形式有许多种;
1. MessageBox:
通过VC编程的对它肯定不会陌生,最开始用消息对话框的时候,我也不知道有这么一个类,是从VC联想到的,才发现了这个类;
MessageBox主要用于系统对用户的提示信息,打开之后,您会发现它是一个非模态的对话框,以下是它的截图和使用的代码;
| MessageBox m = new MessageBox(shell); m.setText("WSC System");//对话框的名称 m.setMessage("不能有两个结束节点");//传达的消息 m.open();//打开这个对话框 /*要注意的就是这种形式的对话框,只能改变对话框的名称和它所传达的消息,它的形式是不可以改变的*/ |
2. FileDialog:
顾名思义,现在讲的一定是处理文件的对话框了;一般的这种对话框右两种形式,一是打开对话框,再一个是保存对话框
来看一个保存对话框的例子;
FileDialog file = new FileDialog(shell,SWT.SAVE);//新建一个文件对话框 file.setText("SAVE"); file.setFilterExtensions(new String[]{"*.grh"});//设置文件过滤器 String isExit = file.open();//打开的对话框返回文件的路径以及文件的名称, 我们可以通过这个字符串来判断保存的时候是否选择了一个文件;当然保存的算法还需要我们来写
|
打开形式的对话框的应用与保存对话框基本上是相同的,它也可以设置文件过滤器,open()这个方法的返回值同样是String类型;不同的是打开对话框的style不是SWT.SAVE,而是SWT.OPEN。
3. 常见的还有ColorDialog,FontDialog等;
4. 有时我们需要使用自定义的对话框,在这个对话框上构建一些组建,其实可以不使用对话框,因为对话框的初始化有些麻烦,我们可以使用一个子Shell,例如
Shell childShell = new Shell(shell);
//shell是childShell的父窗口
我们就可以在这个childShell上设置新的布局以及新的组件
3.3 拖放
1.拖放的基本原理
其中,系统全局变量主要是起标志作用
2.设置拖放源
3.设置拖放目标:
DropTarget dt=new DropTarget(targetPlace,DND.DROP_MOVE);
targetPlace就是拖放目标
4.设置传输数据:
dt.setTransfer(new Transfer[]{TextTransfer.getInstance()});
这里以String为传输数据
5.设置拖放监听
四 一些经典技术与算法
4.1图形拖动
图形的拖动就是图形选中的图形跟着鼠标的移动而不断的相应改变位置,这是在图形界面中是经常见的一个操作,但是在SWT/JFace中来实现却不是意见容易的事。在这里底板是一个Canvas,图形也是建立在一个Canvas上,当然位置的改变是建立在鼠标移动的监听下
l 首先建立几个变量:
Int oldx = -1;// 拖动前的x Int oldy = -1;//拖动前的y Int xoffset = 0; //拖动后的偏移量x Int yoffset =0 ;// 拖动后的偏移量y; Int x,y;// 拖动后图形应该在的位置 |
l 在第一次拖动时,取得oldx和oldy
if(oldX==-1&&oldY==-1){ oldX=e.x; oldY=e.y; } |
l 获得偏移量
xoffset=e.x-oldX; yoffset=e.y-oldY; |
l 得到新的图形位置
x=ca.getBounds().x+xoffset; y=ca.getBounds().y+yoffset; |
l 重新设置图形的位置
ca.setBounds(x,y,ca.getSize.x,ca.getSize.y) |
这样就实现了图形的拖动,不仅算法简洁,而且效果也很好。当然为了更好的效果,还可以加上边界控制,以保证图形不超出边界
4.2图形连线与画线
4.2.1 图形的连线
整个SWT中只有一个类GC与之有关,就是在一个画板上画线,这样简单的线根本无法满足复杂连线的要求,要实现比较复杂的图形间的连线,我们使用了eclipse的另一个插件——draw2D,在draw2D的图形中比较容易实现连线,但是draw2D中连线的图形都是IFigure类的图形,否则就无法实现draw2D内的连线,然而我们的图形使用SWT设计的,因此出现了两者的兼容问题。因此我们自行设计了综合使用两者来实现图形连线的方案,就是图形是用SWT设计的,而线是用draw2D来设计的。这样设计表面看起来能够达到draw2D的两线的完美效果,而又不改变我们需要是用的SWT设计的图形。
l 连线的简化流程
l 解决Canvas与Panel之间的兼容问题
因为我们的建立在一个画布(Canvas)上的,而连线则要建立在一个(Panel)上。因此我们要将两者联系起来,才能实现图形间的连线。这里需要用到轻量级系统(LightweightSystem)
然后就可以新建Panel,并将他设为轻量级系统的内容
这样我们就可以在panel上添加我们的连线了
4.2.2 在面板上画曲线
l 这个曲线也同样要建立在Panel之上,因此也要像上面一样建立Panle,这里不再重复
l 要创建曲线则要用到PolylineConnection(),我们先创建一个PolylineConnection的对象pc.
l 如果要显示箭头,则可以给pc添加修饰,
p2.setTargetDecoration(new PolygonDecoration());
l 接下来就是设置pc上的关键点,包括起点,终点,拐点。确定这些点后,从起点到终点依次排列即可
l 这样就可以建立了曲线,不过线上的个关键点的确定是一个难点,根据不同的情况会有不同的确定方法,这里不能一一列出了
4.3图像常用处理与Canvas
4.3.1 如何在Canvas上添加图像
要在一个画布Canvas上添加,需要注册画布的画图事件,代码如下:
canvas.addPainListener(new PaintListener(){ public void paintControl(PaintEvent e){ e.gc.drawImage(image,10,10); } } |
4.3.2 图像的创建
1. Image(display, “eclipse.gif”)
2. Image (display , “eclipse.gif”,SWT.IMAGE_FRAY)
3.ImageData data = new ImageData(“eclipse.gif);
Image image = new Image(display, data)
4.3.3 图像的放大或缩小
通过ImageData的scaledTo可意见图像放大或缩小,在这里是新建另一个图像,而不是直接改变原来的图像。
ImageData data = image.getImageData(); ImageDate newData = data.scaledTo(newWidth,newHeight); Image newImage = new Image(display, newData); |
4.3.4 图像的保存
4.4文件的过滤
这里所说的文件的过滤不是上面说的文件对话框中的文件的过滤,在这里我们设置了一个树,让它来显示工程下已有的文件,在这里我们只希望看到(.grh)的文件,因此需要给它设置过滤器。先来看看我们怎么实现显示文件的;
在这里使用的是TreeViewer,TreeViewer的构建步骤如下:
u 创建新对象,例如TreeViewer tv=new TreeViewer(fileComposite,SWT.NONE);
u 设置内容管理器,如tv.setContentProvider( new FileTreeContentProvider());
u 设置标签提供器,如tv.setLabelProvider(new FileTreeLabelProvider());
u 设定TreeViewer的输入数据,如tv.setInput(new File("e:/"));
其中FileTreeContentProvide,FileTreeLabelProvider分别是implements了ItreeContentProvider和ILabelProvider两个接口的。
FileTreeContentProvide中有几个重要的方法。
① getElements();"public Object[] getElements(Object inputElement)",当程序开始构建树时,首先调用它返回一个数组,此数组对象表示树的根节点,
② hasChildren();"public boolean hasChildren(Object element)",当TreeViewer显示一个节点(element)后会调用该函数判断当前节点是否有子节点,若有则显示“+”;
③ getChildren();"public Object[] getChildren(Object parentElement)",当用户选择节点打开子节点时,会调用此函数返回下一层子节点,parentElement参数为选择的节点;
④ getparent();"public Object getParent(Object element)"
还有几个方法就不在此叙述,
在程序里不需要显示根目录的位置,只要显示在工程目录下有用的文件,在getElements()方法中,我们返回getChildren()中的值,这样,我们就可以不得到输入的路径这个根节点,而把该路径下的符合条件的文件作为根节点;
public Object[] getElements(Object element) { return getChildren(element); } |
在getChildren方法中,我们通过一个数组列出给定路径下的文件,然后通过一个ArrayList来存储符合条件的文件对象:
Object[] kids = ((File) element).listFiles(); ArrayList<Object> outs = new ArrayList<Object>(); |
当kids不是空的时候,我们就看kids中的文件后缀是不是符合我们的要求,如果是,就添加到outs中
for(int i = 0;i<kids.length;i++){ if(((File)kids[i]).getName().endsWith(".wsdl")|| ((File)kids[i]).getName().endsWith(".bpel")|| ((File)kids[i]).getName().endsWith(".grh")){ int j = 0; outs.add(j,kids[i]); j++; } }
|
现在我们已经得到了我们需要得到的所有的对象,因为这个函数的返回值是个数组,再把outs中的元素复制到一个数组中即可;
f(outs.size()!=0){ Object[] out = new Object[outs.size()]; for(int i= 0;i<outs.size();i++){ out[i] = outs.get(i); } return out; } |
4.5关于序列化保存
1) 关于保存
序列化的问题是由保存引起的,要保存一个对象就必须为相关的类实现序列化,这本没有什么问题,只需要把相关的类继承并实现Serializable接口就可以了,但是,在工程里用到了一些类。例如org.eclipse.swt.widgets.graphics.Image这个类,它是一个final类,不可以被继承,但是他是节点的一部分,必须要显示出来;我们可以把它作为一个参数传到节点的setNodeLocation函数中,它是初始化节点时负责显示的函数。每创建一个新的节点时就需要先创建一个Image实例。
2) 关于恢复
保存成功了还需要恢复图像,恢复图像是个比较复杂的过程,我们要保证图像的位置和数据等许多东西保持不变;首先找到开始节点,从开始节点开始逐个恢复,如没有开始节点,那么这个图是不完整的,就没有办法完整的恢复它;恢复时,不能用原来的对象,因为原有的对象都已经被dispose();了,并且不可以用到任何有关显示的方法,否则就会出现促发异常;所以要得到节点的大小和位置就要另想办法;
为了得到node原来的位置,在node中设置了一个point变量来记载node的位置,并在node的位置更改后更改point的值,这样就可以得到node原来的位置;同理,我们可以得到保存时node的大小了;
我们可以从保存的图中找到与开始节点相关联的下一个节点,回复这个节点后再找下一个节点,这样可以通过一个循环一直找到结束节点,并把这些节点加到一个新建的graph中,然后把相关的信息都通过已有的set和get方法添加的节点中去,这样,整个图的所有的节点都恢复出了;
因为每个节点的下一个节点有不同的可能,用一个if else组合来判断到底是哪一个节点,然后不同的节点有不同的代码;简单的节点如taskNode的恢复比较简单,基本的过程和创建一个新的节点相同,只是注意把原节点的信息传递给新的节点即可;
具体的过程可以简化为
以下是粘贴后初始化一个工作节点的例子;
wfNode = new TaskNode(node.getName(), gra, web); wfNode.setId(node.getId()); wfNode.setNodeInView(c, workspace.getPanel(), attr,workspace,web); BaseWFNodeText.setCanvasText(wfNode); wfNode.setNodeLocation(node.getPoint().x, node.getPoint().y, image1); gra.addNode(wfNode);
|
若下一个节点是复杂节点,首先恢复复杂节点本身,然后判断该节点是否有子节点,若存在子节点,则依次恢复其子节点,通过一个foreach循环就可以把所有的子节点恢复;注意的是每个父节点的子节点形式可能不同,而且他们需要传递的信息也不完全相同。部分代码如下
wfNode.getCanvas().setSize(node.getSize()); //设置节点的大小 wfNode.setSize(node.getSize().x, node.getSize().y); //记录节点的大小 gra.addNode(wfNode); |
节点的信息如下
wfNode.setBpelOperation(node.getBpelOperation()); wfNode.setSuppressJionFaliare(node.getSuppressJionFaliare()); wfNode.setJionCondition(node.isJionCondition()); wfNode.setOporation(node.getOporation()); wfNode.setLink(node.getLink()); //以上为所有节点都有的属性 wfNode.setCondition(node.getCondition()); //FlowNode和WhileNode有的属性 wfNode.setCaseCondiction(node.getCaseCondiction()); //FlowNodeµÄ×Ó½ÚµãÓеÄÊôÐÔ
childNode.setFromPart(element.getFromPart()); childNode.setFromVar(element.getFromVar()); childNode.setToPart(element.getToPart()); childNode.setToVar(element.getToVar()); //以上四个是copy有的节点 |
4.6图形的复制与粘贴
1) 为各个节点以及底层面板创建菜单项,包括复制,粘贴,删除;在工具栏以及菜单栏创建相应的项;
2) 关于复制
复制的方法比较简单,就是把一个新的变量指向要复制的对象,然后把这个变量通过get方法,让外界可以获得它;
public void copy(BaseWFNode node){ midNode = node; } |
3) 关于粘贴
粘贴的过程是创建一个新的节点,他所携带的信息和复制的节点相同
² 获得要粘贴节点的引用;判断是否为空,是就继续,否则就什么也不做;
² 构建一个新的节点,确定节点的id,位置等于声称代码无关的信息;
² 判断节点具体是哪一种节点,并把原节点的信息赋给新的节点;
² Gragh中添加这个节点;
² 根据第三步,若这个节点是某个复杂节点,就把它的子节点也构建出来,并赋予相应的信息;实现的过程和恢复图形类似;
4) 工具栏复制的实现
Ø 这里添加监听的时候用了一个标记,当双击一个节点的时候,就记录这个标记为1,然后让一个中间的变量指向这个节点,
public void mouseDoubleClick(MouseEvent e){ WSCAttribute.showWind(work, node); deleteFlag = 1;//当点击其他地方时设为0; preDelNode = node; } |
Ø 点击复制的时候判断标记是否为1,判断PreDelNode是不是空,不是就根据上面说的复制来执行;删除节点也是用这个思想;
Ø 点击粘贴,判断中间节点是否时空,不是就在底层面板的起始处将节点复制下来;否则就什么也不做;
4.7 用fatJar将SWT/JFace工程打成双击可执行Jar包
1. 下载fatJar插件,解压后有net.sf.fjep.fatjar_0.0.24,将net.sf.fjep.fatjar_0.0.24放到eclipse的plugins中,重新启动eclipse,查看windows->preference,看到一个Fat Jar preference,说明安装成功。
2. 右击工程,Export->other->FatJar Exporter
3. 选定MainClass,将工程需要的Jar包的路径填入classpath中,然后按提示操作。
4. 将工程需要的Jar包放在与fatJar打的Jar包的目录下。
5. 找到eclipse下的plugins下的org.eclipse.swt.win32.win32.x86_3.2.2.v3236,将其解压,
将swt-win32-3236.dll放在Jar包的同一目录下
6将工程需要的图片,文件等放在Jar包的同一目录下
7在机器的系统环境变量配好的情况下,直接双击Jar包就可以运行了