rcp swt jface

借用Eclipse 实现文本内容对比功能

关键字: eclipse compareui

一 相关知识

org.eclipse.compare 插件项目,用于进行文本、源码比对的一个插件,提供了一个Editor或Dialog可方便调用。

 

org.eclipse.compare.CompareEditorInput.CompareEditorInput 是用于给Compare Editor 的EditorInput, 需要自己实现。

org.eclipse.compare.CompareConfiguration 对CompareEditor的配置。是否允许左边内容被修改,或是否允许右边内容被修改;左右两边的label,image等。

 

org.eclipse.compare.ITypedElement 接口,本意为指代有图片、名称、类型的元素。而在Compare中,为一个基本的对比单元。

org.eclipse.compare.IEditableContent 接口,是否可编辑的元素

org.eclipse.compare.IModificationDate 接口,修改时间

org.eclipse.compare.IStreamContentAccessor 获得内容的接口,内容是以InputStream流的方式获得。

org.eclipse.compare.IContentChangeNotifier 内容变化的通知接口

 

org.eclipse.compare.BufferedContent 抽象类,实现了 org.eclipse.compare.IStreamContentAccessor org.eclipse.compare.IContentChangeNotifier 2个接口

在BufferedContent中持有了一个byte[], 表示缓存有界面上修改的内容,当然,最后需要你在CompareEditorInupt中将修改后的byte[]内容保存(比如保存至文件等)

 

 

二 代码

    (1)解决项目依赖

    添加对org.eclipse.compare 的依赖

 

    (2)定义一个表示比对的元素

    可继承与BufferedContent,并实现ITypeElement 等接口。主要代码如下:

    class CompareItem extends BufferedContent implements ITypedElement, IModificationDate, IEditableContent {
        private String fileName;
        private long time;

        CompareItem(String fileName) {
            this.fileName = fileName;
            this.time = System.currentTimeMillis();
        }

        /**
         * @see org.eclipse.compare.BufferedContent#createStream()
         */
        protected InputStream createStream() throws CoreException {
            try {
                return new FileInputStream(new File(fileName));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            return new ByteArrayInputStream(new byte[0]);
        }

        /**
         * @see org.eclipse.compare.IModificationDate#getModificationDate()
         */
        public long getModificationDate() {
            return time;
        }

        /**
         * @see org.eclipse.compare.ITypedElement#getImage()
         */
        public Image getImage() {
            return CompareUI.DESC_CTOOL_NEXT.createImage();
        }

        /**
         * @see org.eclipse.compare.ITypedElement#getName()
         */
        public String getName() {
            return fileName;
        }

        /**
         * @see org.eclipse.compare.ITypedElement#getType()
         */
        public String getType() {
            return ITypedElement.TEXT_TYPE;
        }

        /**
         * @see org.eclipse.compare.IEditableContent#isEditable()
         */
        public boolean isEditable() {
            return true;
        }

        /**
         * @see org.eclipse.compare.IEditableContent#replace(org.eclipse.compare.ITypedElement, org.eclipse.compare.ITypedElement)
         */
        public ITypedElement replace(ITypedElement dest, ITypedElement src) {
            return null;
        }

        public void writeFile() {
            this.writeFile(this.fileName, this.getContent());
        }

        private void writeFile(String fileName, byte[] newContent) {
            FileOutputStream fos = null;
            try {
                File file = new File(fileName);
                if (file.exists()) {
                    file.delete();
                }

                file.createNewFile();

                fos = new FileOutputStream(file);
                fos.write(newContent);
                fos.flush();

            } catch (IOException e) {
                e.printStackTrace();

            } finally {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                fos = null;
            }
        }
    }

 

    (3)配置CompareConfiguration

        CompareConfiguration config = new CompareConfiguration();
        config.setProperty(CompareConfiguration.SHOW_PSEUDO_CONFLICTS, Boolean.FALSE);

        // left
        config.setLeftEditable(true);
        config.setLeftLabel("Left");

        // right
        config.setRightEditable(true);
        config.setRightLabel("Right");
 

 

    (4)定义CompareEditorInput

        CompareEditorInput editorInput = new CompareEditorInput(config) {
            CompareItem left = new CompareItem("C:/A.txt");
            CompareItem right = new CompareItem("C:/Inject.log");
            
            @Override
            protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                return new DiffNode(null, Differencer.CONFLICTING, null, left, right);
            }

            @Override
            public void saveChanges(IProgressMonitor pm) throws CoreException {
                super.saveChanges(pm);

                left.writeFile();
                right.writeFile();
            }
        };

        editorInput.setTitle("文件比较");

 

   (5)弹出Compare Editor或Dialog

CompareUI.openCompareEditor(editorInput);  // 打开对比Editor

CompareUI.openCompareDialog(editorInput); // 弹出对比Dialog
 

三 效果

 

(1)Editor效果

Compare效果图

 

 

(2)Dialog效果

Compare Editor

 

 

四 其他

    (1) 代码是基于Eclipse插件项目的email Template 创建的, 可直接使用附件中的源码替换到默认生成的类。

    (2) 代码演示了在Eclipse RCP环境下使用Compare功能。

2009 - 09 - 23

SWT的图片叠加效果

关键字: image overlay icon

一. 核心类说明

 

ImageDescriptor用于表示一个可用于创建org.eclipse.swt.graphics.Image的类
CompositeImageDescriptor可用于创建出自定义图像效果的Image的抽象类
DecoratorOverlayIcon这是org.eclipse.ui.internal.decorators下的类,很可惜,它是package的class,不可外部调用
OverlayIcon用于创建出2个图片叠加效果的类. 不过, 只可以做”右上”的叠加
OverlayImageDescriptor我自己扩展OverlayIcon类,简单的支持”上左”,”上右”,”下左”,”下右”. 而不是OverlayIcon只可以做”右上”的叠加



二. 代码说明

  1. OverlayImageDescriptor.java 实现类
  2. MainShell 可运行类

见源码

 


三. 原始图片


四. 效果截图

 

2009 - 08 - 08

TreeViewer的ContentProvider详解,以及Lazy载入

关键字: treeviewer lazy pending contentprovider
为了实现这样的效果:
    载入的过程中,显示Pending。


    载入完毕,Pending消失。

   

我们先从基础的说起,先来看ITreeContentProvider 接口:
public interface ITreeContentProvider {
	public Object[] getElements(Object inputElement) ;
	public Object[] getChildren(Object parentElement) ;
	public boolean hasChildren(Object element) ;
	// ...
}

    getElements 表示在setInput(Object)的时候,如何从Object中得到一个数组,而使用这个数组去将树的第一层结点显示出来。这个方法只在setInput时才使用一次。
    getChildren表示在每次展开树的节点时,如果得到下一级节点的值,当然,树的节点展开了一次就不会再调用这个方法了,因为在树节点对应的控件TreeItem中,已经创建好了子节点控件了。
    hasChildren就是判断当前节点是否有子节点,有的话,就显示+号。

ITreeContentProvider的使用类型可以分成3种(我自己分的,^-^)。
1。简单模式
2。Lazy Loader模式(简单)
3。Lazy Loader模式(显示Pending)


一. 简单模式
其实就是在setInput的模型中,已经预先将所有的子模型都载入完毕,而不用再动态的载入子模型了。
模型说明:
    这个模型代表树节点,是支持父子结构的。当然,在Jface里面是有一个TreeNode的,org.eclipse.jface.viewers.TreeNode,相应的还提供了一个org.eclipse.jface.viewers.TreeNodeContentProvider。
public class TreeNode {
	private TreeNode parent;
	private List<TreeNode> children = new ArrayList<TreeNode>();
	private Object value;


ContentProvider代码:
	public class SimpleContentProvider implements ITreeContentProvider {
	public Object[] getElements(Object inputElement) {
		return ((TreeNode) inputElement).getChildren().toArray();
	}
	public Object[] getChildren(Object parentElement) {
		return ((TreeNode) parentElement).getChildren().toArray();
	}
	public boolean hasChildren(Object element) {
		return ((TreeNode) element).getChildren().size() > 0;
	}


构建setInput的模型
就是在构建模型的时候,将所有的子模型都加载好了:
	private TreeNode buildLazyContent() {
		TreeNode root = new TreeNode(null);
		TreeNode level_1_1 = new TreeNode("1.1");
		root.addChild(level_1_1);
		// ...
		return root;
	}


其他代码:
		viewer.setLabelProvider(new TreeViewerLabelProvider());
		viewer.setContentProvider(new SimpleContentProvider());
		viewer.setInput(this.buildSimpleContent());



二. Lazy Load模式(简单)
在setInput的模型中,只有最顶层的模型,再每次点击+的时间,将下一层的模型动态的载入,从而将树的子节点构造出来。也就是在getChildren中动态载入即可。

ContentProvider代码。
    注意getChildren 和hasChildren的方法实现,hasChildren返回true,表示需要给这个树节点显示+号。点击+号,getChildren会动态的载入子节点数据,这样就实现了Lazy Load了。
public class SimpleLazyContentProvider implements ITreeContentProvider {
	public Object[] getChildren(Object parentElement) {
		TreeNode parent = (TreeNode) parentElement;
		this.loadChildren(parent); 
		return parent.getChildren().toArray();
	}
	public boolean hasChildren(Object element) {
		return true; 
	}
	private void loadChildren(TreeNode parent) {
		TreeNode child_1 = new TreeNode("1");
		parent.addChild(child_1);
		
		TreeNode child_2 = new TreeNode("2");
		parent.addChild(child_2);
	}



构建setInput的模型:
    只需要构建第一层树节点即可,后面的就交给ContentProvider去处理。
	private TreeNode buildSimpleLazyContent() {
		TreeNode root = new TreeNode(null);
		TreeNode level_1_1 = new TreeNode("1.1");
		root.addChild(level_1_1);
		return root;
	}


其他代码:
		viewer.setLabelProvider(new TreeViewerLabelProvider());
		viewer.setContentProvider(new SimpleLazyContentProvider());
		viewer.setInput(this.buildSimpleLazyContent());



三. Lazy Loader模式(显示Pending)
   和模式是二一样的,都是点+载入子模型。但是,如果是需要长时间的加载,模式二会将界面卡住,而这个模式,再点击+号后,会先显示一个Pending树节点(并可以显示进度条),并看到随着数据一个一个载入树节点一个一个添加出来,所有数据都载入后,Pending树节点消失,这样用户体验就会好很多。在这个模式,需要用到很多其他的类,具体看代码:

模型代码:
1. 需要实现IDeferredWorkbenchAdapter接口。
2. 注意fetchDeferredChildren方法。将载入子数据的过程放到了模型里面(很怪)。
public class PendingTreeNode extends TreeNode implements IDeferredWorkbenchAdapter {
	public void fetchDeferredChildren(Object object, IElementCollector collector,
			IProgressMonitor monitor) {
		PendingTreeNode parent = (PendingTreeNode) object;
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		PendingTreeNode node1 = new PendingTreeNode("1");
		parent.addChild(node1);
		collector.add(node1, monitor);
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		PendingTreeNode node2 = new PendingTreeNode("2");
		parent.addChild(node2);
		collector.add(node2, monitor);
	}


ContentProvider代码。
1. 添加了一个DeferredTreeContentManager,并使用该manager代理getChildren方法。
2. hasChildren返回true。
3. 修改了getElements方法。
public class PendingLazyContentProvider implements ITreeContentProvider {
	private DeferredTreeContentManager manager;
	
	public Object[] getChildren(Object parentElement) {
		return manager.getChildren(parentElement);
	}
	public boolean hasChildren(Object element) {
		return true;
	}
	public Object[] getElements(Object inputElement) {
		if (inputElement instanceof PendingTreeNode) {
			return ((PendingTreeNode) inputElement).getChildren().toArray();			
		} 
		return new Object[0];
	}
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		if (manager == null) {
			manager = new DeferredTreeContentManager(this, (TreeViewer) viewer);
		}
	}
}


LabelProvider代码:
1. 修改了getText方法。由于我们说中间会创建一个显示Pending的节点,这个节点就是PendingUpdateAdapter,需要特别指定显示的text。
public class PendingTreeViewerLabelProvider extends LabelProvider {
	public String getText(Object obj) {
		if (obj instanceof TreeNode) {
			return ((TreeNode) obj).getValue().toString();
		} else if (obj instanceof PendingUpdateAdapter) {
			return ((PendingUpdateAdapter) obj).getLabel(null); 
		}
		return obj.toString();
	}


构建setInput的模型:
1. 只需要预先放入根节点即可。子节点的载入就依赖于点击+号,lazy载入了。
	private PendingTreeNode buildPendingLazyContent() {
		PendingTreeNode root = new PendingTreeNode(null);

		PendingTreeNode level_1_1 = new PendingTreeNode("1.1");
		root.addChild(level_1_1);
		return root;
	}



其他代码:
		viewer.setLabelProvider(new PendingTreeViewerLabelProvider());
		viewer.setContentProvider(new PendingLazyContentProvider());
		viewer.setInput(this.buildPendingLazyContent());



四. 总结
1. 简单模式适合于你一次性将数据全部载入,而后在setInput一次显示出来。
2. Lazy Load模式(简单)适合于性能影响不大的点击+号Lazy的载入数据。
3. Lazy Load模式(显示Pending)适合于载入过程比较长,为了提供用户交互而使用
4. Lazy Load模式都存在着遍历的问题。因为有的模型的子节点还没有完全载入,而你却依赖所有这些子节点的时候,这时就必须在代码里面将所有子节点打开,让其载入所有子数据至最后一层,对于(简单)和(显示Pending)都可以这么去做。
5. 还是4的情况,由于(显示Pending)是异步载入的,需要更复杂的判断,并基于线程去判断某节点是否载入完毕,等你自己去实现的时候,你会发现这是有多复杂的^-^


五. 其他相关的类
org.eclipse.jface.viewers.TreeNode
org.eclipse.jface.viewers.TreeNodeContentProvider
org.eclipse.jface.viewers.ArrayContentProvider
org.eclipse.ui.progress.IDeferredWorkbenchAdapter
org.eclipse.ui.progress.DeferredTreeContentManager
  • 描述: 显示pending
  • 大小: 11.7 KB
  • 描述: 载入完成
  • 大小: 12.3 KB
2009 - 07 - 15

SWT多线程

关键字: swt 多线程
一:基本概念
在SWT内,有一个UI主线程的概念,自定义的线程不可操作UI控件,如果要操作则必须使用
display.asyncExec(new Runnable() {
	public void run() {
             // UI操作
	}
});

需要注意的是:在Display.asyncExec()方法内运行的线程就是UI主线程,而不是用户自定义的线程。通过简单的实验可以知道,可见附件。


二:Display.asyncExec与Display.syncExec
display.asyncExec(new Runnable() {
	public void run() {
           // UI操作
	}
});

Display.asyncExec()方法,下面的代码可以继续执行,而不用等到Display.asyncExec()的完成。

display.syncExec(new Runnable() {
	public void run() {
           // UI操作
	}
});

Display.syncExec()方法,会让在下面的代码进入等待,需要等到Display.syncExec()的完成才可以继续向下执行。


三:Job与UIJob
1. Job与UIJob都必须工作在eclipse环境下,也就是Eclipse或RCP环境下。
2. 提供了进度条,子任务,状态等功能。
3. UIJob extends Job,UIJob是对Job的简单封装,使得任务运行于Display.asyncExec()方法内。

Job uploadJob = new Job("Job...") {
    protected IStatus run(IProgressMonitor monitor) {
        // 非UI线程,只能进行非UI的操作
    }
}

UIJob dbJob = new UIJob("UIJob...") {
    public  IStatus runInUIThread(IProgressMonitor monitor){
        // UI主线程,可进行UI操作
    }
}

当然,需要在Job内进行UI操作,只需要使用Display.asyncExec或Display.syncExec即可。


四:IProgressService的busyCursorWhile与runInUI

IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
      public void run(IProgressMonitor monitor) {
         // 非UI线程,只能进行非UI的操作
      }
   });

progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
            // UI主线程,可进行UI操作
         }
      },
      Platform.getWorkspace().getRoot());



五:Job的状态监听
Job的状态监听,涉及到一个接口IJobChangeListener,或者空实现类JobChangeAdapter。
IJobChangeListener用于对Job的状态进行监听,比如:开始执行,完成,睡眠等状态改变的时候。


六:Job异常处理
异常的处理可以有不同:
1. 将异常直接抛出来:在Job执行过程中,返回带有Exception的Status。
		protected IStatus run(IProgressMonitor monitor) {
			try {
				doJob(monitor); // false
			} catch (Exception e) {
				return new Status(Status.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
			}
			return Status.OK_STATUS;
		}
	};


2. 所有Job完成后进行错误提示:在Job执行过程中,可以将异常保存起来,并借助于IJobChangeListener的done进行job完成后的操作,比如进行异常提示等操作。
job.addJobChangeListener(new JobDoneListener());

class JobDoneListener extends JobChangeAdapter {
		@Override
		public void done(IJobChangeEvent event) {
			if (exception != null) {
				exception.printStackTrace();
			}

2009 - 06 - 03

去掉plugin_customization.ini文件,在代码中实现配置功能

关键字: eclipse rcp plugin_customization.ini 配置

一. 常规做法
    在Eclipse RCP项目中, 可以在根目录创建一个plugin_customization.ini文件, 里面写入特定配置, 比如:

org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP = true


这个具体变量名和变量的取值, 可以见: org.eclipse.ui.IWorkbenchPreferenceConstants 里面有详细说明.

 

二. 去掉plugin_customization.ini文件

下面就说, 怎么在代码里面进行配置的实现, 而不是依赖于一个plugin_customization.ini配置文件. 具体操作很简单, 只需要在你自己的WorkbenchAdvisor#initialize() 里面去对依赖项目进行赋值即可.实现代码如下:

 

public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
	/* (non-Javadoc)
	 * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize(org.eclipse.ui.application.IWorkbenchConfigurer)
	 */
	public void initialize(IWorkbenchConfigurer configurer) {
		PlatformUI.getPreferenceStore().setDefault(
			IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP, true);
		PlatformUI.getPreferenceStore().setDefault(
			IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS, false);
	}
}
 


三. 特殊变量说明

  1. SHOW_PROGRESS_ON_STARTUP           在splash的画面中, 是否显示进度条
  2. DISABLE_NEW_FAST_VIEW                   是否禁止左下角的Show View As a Fast View按钮
  3. SHOW_MEMORY_MONITOR                    是否显示内存情况, 并可进行GC操作, 这个比较有意思
  4. SHOW_OPEN_ON_PERSPECTIVE_BAR    在PerspectiveBar上,是否显示New Perspective按钮
  5. SHOW_TEXT_ON_PERSPECTIVE_BAR     在PerspectiveBar上,是否显示Perspective的名称
  6. SHOW_TRADITIONAL_STYLE_TABS         Editor或ViewPart是否使用传统的Tab的样式. 这个肯定用true, false的太老土了.
  7. DOCK_PERSPECTIVE_BAR                      PerspectiveBar的显示位置, 左上 还是 右上.

 

 

2009 - 05 - 06

StyledText 的Traverse,VerifyKey,MouseListener分析

关键字: styledtext traverselistener verifykeylistener mouselistener
目标功能:
    随便焦点的跳转(键盘的上下左右操作;键盘的PgUp、PgDown操作;鼠标的点击操作),得到焦点所在位置的Style信息。


StyledText可以添加TraverseListener, 表示对界面上的焦点移动的监听.
getStyledText().addTraverseListener(new TraverseListener() {
			public void keyTraversed(TraverseEvent e) {

			}
		});


一般的处理代码都是对event.detail进行判断,再进行对应的操作, 代码如下:
		switch (event.detail) {
			case SWT.TRAVERSE_NONE:
			case SWT.TRAVERSE_ESCAPE:
			case SWT.TRAVERSE_RETURN:
			case SWT.TRAVERSE_TAB_PREVIOUS:
			case SWT.TRAVERSE_TAB_NEXT:
			case SWT.TRAVERSE_ARROW_PREVIOUS: // 上 或 左
			case SWT.TRAVERSE_ARROW_NEXT: // 下 或 右
			case SWT.TRAVERSE_MNEMONIC:
			case SWT.TRAVERSE_PAGE_PREVIOUS:
			case SWT.TRAVERSE_PAGE_NEXT:
		}


但通过调试分析后发现:
event.keyCode
只监听 SWT.ARROW_LEFT, SWT.ARROW_RIGHT, SWT.ARROW_UP, SWT.ARROW_DOWN有效(也就是键盘上的上、下、左、右), 对于SWT.PAGE_UP, SWT.PAGE_DOWN都无效(也就是PgUp、PgDown按键)。

TraverseListener是不能用了, 因为PgUp、PgDown也会让界面的焦点移动,但却无法得到监听。于是,考虑换用 VerifyKeyListener MouseListener的组合来完成该需求。


VerifyKeyListener
对StyledText界面上的按键进行监听。能监听所有的按键操作。


MouseListener
对界面上的鼠标按下、鼠标弹起等进行监听。


具体实现就比较简单了:
getStyledText().addMouseListener(new MouseAdapter() {
			public void mouseUp(MouseEvent e) {
                             showCaretStyle();
			}
		});
getStyledText().addVerifyKeyListener(new VerifyKeyListener() {
			public void verifyKey(VerifyEvent event) {
                             if (isTraverseKey(event.keyCode) {
                                 showCaretStyle();
                             }
			}

	private boolean isTraverseKey(int keyCode) {
		if (event.stateMask == 0) {
			if (SWT.ARROW_LEFT == event.keyCode || SWT.ARROW_RIGHT == event.keyCode || SWT.ARROW_UP == event.keyCode || SWT.ARROW_DOWN == event.keyCode
					|| SWT.PAGE_UP == event.keyCode || SWT.PAGE_DOWN == event.keyCode) {
				return true;
			}
		}
		return false;
	}

		});

	protected void showCaretStyle() {
		int caretOffset = dialog.getStyledText().getCaretOffset();
                StyleRange beforeStyle = getCaretBeforeStyle(caretOffset);
                System.out.println(beforeStyle);
        }

	private StyleRange getCaretBeforeStyle(int caretOffset) {
		if (caretOffset > 0) {
			caretOffset--;
		}
		StyleRange[] styleRanges = this.dialog.getStyledText().getStyleRanges(caretOffset, 1);
		if (styleRanges.length > 0) {
			return styleRanges[0];
		} else {
			return null;
		}
	}


但问题来了,因为:int caretOffset = dialog.getStyledText().getCaretOffset();得到的还是在焦点移动前的caretOffset,而不是焦点移动后的caretOffset,这也比较好理解,因为在MouseListener、VerifyKeyListener里面,焦点还没有移动呢,你当然只可以拿到移动前的caretOffset了。


解决方法:让得到Style的线程sleep(100)再去获得caretOffset,这样就可以得到焦点移动后的caretOffset了。关键代码如下:
		Display.getCurrent().asyncExec(new Runnable() {
			public void run() {
				// 先等待100ms,让按键事件、鼠标点击事件先执行完成,焦点移动到新的位置上
				try {
					Thread.sleep(100);
				} catch (Exception e) {
					e.printStackTrace();
				}

				// 再得到新的焦点所在位置的Style信息
				showCaretStyle();
			}
		});
2009 - 04 - 19

Java在Eclipse环境下调用Subclipse接口完成SVN操作(附源码)

关键字: java svn eclipse rcp subclipse
Java在Eclipse环境下调用Subclipse接口完成SVN操作(附源码)

在Eclipse环境中使用SVN还是比较简单的, 因为已经Subclipse已经对SVN的操作进行了封装,只需要给你的Eclipse应用添加Subclipse,然后你自己的插件项目再对Subclipse进行依赖即可。具体实现如下:

一. 给Eclipse添加Subclipse插件
Subclipse下载地址:http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240

二. 新建EclipseRCP项目

三. 给Plugin项目添加依赖的Subclipse插件
a) org.tigris.subversion.clientadapter
b) org.tigris.subversion.clientadapter.javahl
c) org.tigris.subversion.clientadapter.javahl.win32
d) org.tigris.subversion.subclipse.core


四. 关键类说明
a) SVNRepositoryInfo
我自己定义的一个用于放置SVN信息的一个JavaBean
b) SVNRepositoryUtil
我自己定义的一个调用SVN的Util类
c) ISVNClientAdapter
在客户端操作SVN的具体的类
d) SVNUrl
代表SVN地址的一个类
e) ISVNNotifyListener
对SVN执行的每一步操作的监听
f) JhlClientAdapterFactory
Subclipse用于注册JHL依赖的dll的类


五. 关键代码说明
JhlClientAdapterFactory.setup();

该代码用于注册JHL所依赖的一些dll文件,所以,该方法只可以执行一次,dll注册完成后不可再执行,否则会有异常。具体JHL依赖的dll文件可以见:
eclipse/plugins/org.tigris.subversion.clientadapter.javahl.win32_1.X.X.X文件夹

String bestClientType = SVNClientAdapterFactory.getPreferredSVNClientType();
ISVNClientAdapter svnClient = SVNClientAdapterFactory.createSVNClient(bestClientType);

其实这段代码的含义是说,找到Subclipse可使用的SVNClient。
这里所谓的可用的SVNClient指的是:Subclipse提供了两种对SVN操作的liberary,一个是JHL,对应于org.tigris.subversion.clientadapter.javahl插件,一个是SVNKIT,对应于org.tigris.subversion.clientadapter.svnkit_1.6.0.1.jar插件。但事实上,SVNKit不可用,因为该插件没有对外Export任何Package。

svnClient.addNotifyListener(new SVNNotifyListener());
	
public class SVNNotifyListener implements ISVNNotifyListener {
	public void setCommand(int cmd) {
	}
	public void logMessage(String message) {
		System.out.println("Message :" + message);
	}
	public void logCommandLine(String message) {
		System.out.println("CommandLine :" + message);
	}
	// …
}


ISVNNotifyListener是需要去实现的对SVN操作的监听事件。比如,在一次commit过程中,可能提交了很多文件,删除了几个文件,更新了几个文件,那么对于这样的一个过程中的小事件提供监听的功能。

SVNRevision
这是用于表示Svn版本的类,比如HEAD,BASE,或者文件后面的数字版本,或者时间版本 等。

方法参数中的recurse
指的是,如果是一个文件夹是否需要将其下面的所有子文件夹、子文件一起遍历出来,或者一起进行操作。

SVNUrl moduleUrl = new SVNUrl(repositoryInfo.getUrl() + moduleName);
svnClient.checkout(moduleUrl, destPath, revision, true);

这段就不解释了,很容易明白。

更详细的代码请下载源代码。

源代码基于Eclipse3.4,Subclipse1.6。在Eclipse3.3中进行少量修改也能使用。
项目基于Eclipse RCP,运行iwoo.svn.product,在ToolBar点击Checkout按钮即可在Console查看到输出结果,比如下面的日志:
CommandLine :checkout http://iwoo.googlecode.com/svn/trunk/temp.withsvn -r HEAD --depth=infinity --force
Message :A   C:/A/B/C/.classpath
Status of C:/A/B/C/.classpath has changed
Message :A   C:/A/B/C/.project
Status of C:/A/B/C/.project has changed
2009 - 04 - 07

JFace的FieldDecoration / DecoratedField 使用详解

关键字: jface fieldassist fielddecoration decoratedfield
关键代码:

		IControlCreator controlCreator = new IControlCreator() {
			public Control createControl(final Composite parent, final int style) {
				Text text = new Text(parent, style);
				return text;
			}
		};
                
                // 声明一个FieldDecoration, 注意命名, 不要和DecoratedField混淆. 指的是具体的小Tip的控件. 
                // 可以自定义提示信息, 提示图片.
		final FieldDecoration decoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
		decoration.setDescription("Please Input 'OK'");
		// decoration.setImage(image);

		final DecoratedField decoratedField = new DecoratedField(shell, SWT.BORDER, controlCreator);

		// DecoratedField.getLayoutControl()得到的是一个Composite,你的Control就是创建在这个Composite之上的.
		// 可以对这个Composite进行外围的布局.
		// 里面的Control是无法控制布局的, 是默认FormLayout, 且是占满整个Composite.
		decoratedField.getLayoutControl().setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

		// DecoratedField 的position
		// 左右: SWT.LEFT, SWT.RIGHT
		// 上下: SWT.TOP,SWT.BOTTOM
		// 使用上下和左右进行组合, 比如 SWT.RIGHT | SWT.TOP
		decoratedField.addFieldDecoration(decoration, SWT.RIGHT | SWT.TOP, false);
		decoratedField.hideDecoration(decoration);
                
                // 给这个Text添加Modify事件, 通过内容判断修改decoratedField的表现状态.
		((Text) decoratedField.getControl()).addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				Text text = (Text) e.widget;

				if (text.getText().trim().equals("") || text.getText().trim().toUpperCase().equals("OK")) {
					decoratedField.hideDecoration(decoration);
					decoratedField.hideHover();

				} else {
					decoratedField.showDecoration(decoration);
					decoratedField.showHoverText("Not OK !");
				}
			}
		});


具体见代码里面的注释就可以明白了, 蛮简单的.
2009 - 03 - 26

NightLabs 开源的swt pdf viewer (Eclipse plugin)

关键字: nightlabs pdf viewer swt eclipse plugin
http://wiki.nightlabs.de/en/PDF_Viewer:Integration

找来找去, 全是Swing的, 终于找到一个swt的, 而且还是Eclipse的plugin. sf的项目, 肯定是免费, 开源的. 但是它是JDK1.6的, 爆汗~``


2009 - 02 - 12

有关于《OSGI进阶》中的org.eclipse.equinox.servlet.api.jar

关键字: osgi进阶 org.eclipse.equinox.servlet.api.jar
具体可以参见JavaEye问答频道:
http://www.javaeye.com/problems/11150


问题:
引用
关于《OSGI实战》与《OSGI进阶》中关于
org.eclipse.equinox.servlet.api.jar
这个JAR包是因为时间关系更换了名字还是怎么的,
我找了很久没有找到这个JAR的下载链接.我在官网上也找过,就是没有.



解答:
文章是基于Eclipse3.2写的, 在Eclipse3.2上是可以找到的,比如我的就是:
org.eclipse.equinox.servlet.api_1.0.0.v20060601.jar

在Eclipse3.4中为什么找不到,其实这中间藏着一个小秘密,
Eclipse3.2中的org.eclipse.equinox.servlet.api.jar
其实就是直接从 Tomcat 4.1.30中拿的 servlet.jar
你可以见org.eclipse.equinox.servlet.api.jar中的about.html

而在Eclipse3.4中,已经直接用回了原来的名字:
javax.servlet_2.4.0.v200806031604.jar
你可以见javax.servlet.jar中的about.html
2009 - 01 - 15

Eclipse在创建Plug-in项目时的Target platform选项的说明

关键字: eclipse plug-in target platform
Target PlatForm 插件的运行平台.

Eclipse version 指的是Eclipse UI 插件这样的运行方式.

an OSGI framework 指的是运行于OSGI下的,非UI的插件.
    选项: Equinox 指的是,使用Equinox(Eclipse的OSGI实现)
    选项: standard 指的是,使用标准的OSGI实现



下面具体说明他们的差别:

1. 自动生成代码的区别:

选择 Eclipse version, 那么默认生成的Activator就是继承与AbstractUIPlugin.
public class Activator extends AbstractUIPlugin {
	public static final String PLUGIN_ID = "lggege.eclipse"; // The plug-in ID
	private static Activator plugin; // The shared instance
	public Activator() { }
	/*
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
	}
	/*
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}
	public static Activator getDefault() {
		return plugin;
	}
}

注: AbstractUIPlugin 实现了BundleActivator接口.


选择 Equinox或者 standard, 那么默认的Activator就是实现了BundleActivator接口.
public class Activator implements BundleActivator {
	/*
	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
	}
	/*
	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
	}
}


看出一定的区别了吧, 基于Ecliopse平台和OSGI平台(Equonix和Standard), 最终都是基于OSGI. 只是Ecliopse平台还是实现的OSGI.


2. 对于IDE的区别:
Eclipse version,打开的MANIFEST.MF的编辑器, 它有Extensions 和 Extension Points这两个设置页面.

Equinox或者 standard,开的MANIFEST.MF的编辑器, 是没有Extensions 和 Extension Points这两个设置页面.


这也说明一个区别: Ecliopse平台不仅仅实现了OSGI, 同时, 还使用了自己的Plugin机制, 也就是Extensions和Extensions Points机制.

也就是Eclipse并不是一个完全的OSGI, 而是一个OSGI 与 自己的Plugin机制的结合体.


Equinoxstandard对于IDE没有什么区别, 也许只是提供一个功能,给你日后选择一个具体的OSGI平台留下的扩展吧.

后记:
发现Eclipse的Help里面有一些相关的信息:
引用
Eclipse vs. OSGi Framework
The Eclipse vs. OSGi framework choice acts as pre-filter to determine what initial pages will be visible in the plug-in manifest editor when it opens.

Since the extension registry is Eclipse-specific content, the Extensions and Extension Points pages of the manifest editor are visible only when the Eclipse version option is chosen.

Equinox vs. Standard
When targeting an OSGi framework, you have a choice between the Equinox and standard frameworks. The Equinox OSGi framework augments the MANIFEST.MF content with Eclipse-specific headers (e.g. Eclipse-LazyStart) and directives (e.g. x-friends). If you do not wish to use these Eclipse-specific headers and attributes, then choose the standard option.


可参见:
http://www.ibm.com/developerworks/cn/opensource/os-ecl-osgi/index.html
  • 描述: Target platform
  • 大小: 10.4 KB
2009 - 01 - 09

eclipse中的线程

关键字: eclipse 线程
见: http://www.eclipseworld.org/bbs/read-cec-tid-1804.html

确实是好文章, 收藏一下. 

寒假我就上网很少了,真的非常不好意思.eclipse中的线程是开发eclipse插件中一个比较重要的基础,而很多书上都没有说,我最后抽时间写了这篇入门文章,希望对大家有帮助.

我先大致讲一讲GUI程序中的线程.
    虽然各个操作系统之间的线程机制是不一样的,但是大致是相同的.当用户使用GUI程序时,如果点鼠标或按下键盘上的键等时,操作系统会产生对应的GUI事件,它来决定哪个窗口或程序来接受每一个事件并且放到程序的事件队列中.
    任何GUI程序的底层结构就是一个事件循环.程序首先初始化事件循环,并开始循环,这个循环会从事件队列依次接收GUI事件并一一做出相应的反应.程序应该对事件做出快速的反应使程序一直对用户有响应,举个例子,用户点了一下程序里的一个按钮结果程序就没反应了,那么这个程序应该算是一个失败的程序吧.
    如果某个UI事件引发了某个需要长时间的事务,那么应该把它放到一个另外的单独的线程中,这样程序的那个事件循环就能够马上回来响应用户的下一个操作.线程是非常复杂的一个主题,如果处理的不好很容易造成死锁等很糟糕的情况.

    还好,eclipse为我们开发插件提供了一个方便的UI线程包,大大的简化了很多底层复杂的东西.先看看几个简单的概念.
1.SWT UI线程
SWT用的是操作系统直接支持的线程模式,程序会在主程序里运行一个时间循环并依次在这个线程里响应事件.看下面这段代码,UI线程就是创建Display的那个线程.
public static void main (String [] args) {
    Display display = new Display ();
    Shell shell = new Shell (display);
    shell.open ();
    // 开始事件循环
    // 关掉窗口后
    while (!shell.isDisposed ()) {
      if (!display.readAndDispatch ())
        display.sleep ();
    }
    display.dispose ();
  }

简单的小程序里,一个UI线程就能够满足需要了.
但如果是长时间的操作,你就最好不要用UI线程来做这些事,可以交给Job去做.它其实就是另外启动的线程,也就是等会我要说的非UI线程.

2.Job
Job类由org.eclipse.core.runtime插件提供.它能够让客户程序员轻松的在另外的线程中执行代码.
看一个小例子
Job job = new Job("My First Job") {
  protected IStatus run(IProgressMonitor monitor) {
      System.out.println("Hello World (from a background job)");
      return Status.OK_STATUS;
    }
  };
job.setPriority(Job.SHORT);
job.schedule(); // start as soon as possible

Job的默认优先级是Job.Long,这里例子中的优先级要比它高.
只要调用Job#schedule(),它就会尽快在另外的线程中运行run()中的代码.
再看一个小例子:
final Job job = new Job("Long Running Job") {
    protected IStatus run(IProgressMonitor monitor) {
      try {
        while(hasMoreWorkToDo()) {
          // do some work
          // ...
        if (monitor.isCanceled()) return Status.CANCEL_STATUS;
        }
        return Status.OK_STATUS;
      } finally {
        schedule(60000); // start again in an hour
      }
    }
  };
job.addJobChangeListener(new JobChangeAdapter() {
    public void done(IJobChangeEvent event) {
    if (event.getResult().isOK())
      postMessage("Job completed successfully");
      else
        postError("Job did not complete successfully");
    }
  });
job.setSystem(true);
  job.schedule(); // start as soon as possible

monitor 是一个进度显示条,它会在运行job时自动显示,如果任务成功运行完成,返回Status.OK_STATUS,如果中途被用户在进度显示条那里中断,就返回Status.CANCEL_STATUS.上面schedule(60000);它是让job每过1小时就自动运行,Job又一个非常强大的功能.
然后后面是可以给job添加监听器.
job.setSystem(true);这一句是把这个job设置为系统级别的.如果调用setUser(true),那么就被定义为用户级别的,用户级别和默认级别的job
    在运行时会以UI形式反映出来,如果是用户job,那么会弹出一个进度显示窗口,能让用户选择在后台里运行.
下图是一个job自动运行时的效果:

再介绍job常常用到的一个方法Job#join().
系统调用到某个job,调用它的run()方法:
再看下面这个例子:

  class TrivialJob extends Job {
    public TrivialJob() {
      super("Trivial Job");
    }
    public IStatus run(IProgressMonitor monitor) {
      System.out.println("This is a job");
      return Status.OK_STATUS;
    }
  }

  job的创建和计划如下所示:

  TrivialJob job = new TrivialJob();
  System.out.println("About to schedule a job");
  job.schedule();
  System.out.println("Finished scheduling a job");

  他们的执行是和时间没关系的,输出可能如下:
  About to schedule a job
  This is a job
  Finished scheduling a job

也可能是:

  About to schedule a job
  Finished scheduling a job
  This is a job


  如果希望某个job运行完成后在继续时,可以使用join()方法.
  join()会一直阻塞到该job运行完.

例子:
  TrivialJob job = new TrivialJob();
  System.out.println("About to schedule a job");
  job.schedule();
  job.join();
  if (job.getResult().isOk())
    System.out.println("Job completed with success");
  else
    System.out.println("Job did not complete successfully");

上面的代码执行后,输出应该就是这样:

  About to schedule a job
  This is a job
  Job completed with success

Job的功能是很强大的,还有很多功能我以后会介绍,也可以查阅官方帮助文档.这里先把几个常用的问题解决掉.
参见:
http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/runtime_jobs.htm

3.如果在Job中加上改变UI的代码就会失败.
原因如下:
如果是在非UI线程中调用UI,SWT就会抛出一个SWTException.
要在一个非UI线程改变UI的话有几种技术:

第一种,用:
Display#syncExec(Runnable)或
Diaplay#asyncExec(Runnable)

第二种:
已经开发了另外一种Job,就是UIJob,可以直接在它里面运行改变UI的代码,其实它就是在SWT的asyncExec()方法里运行的.所有继承UIJob的类应

该覆写runInUIThread方法而不是run方法.

3.关于进度显示
在Jface中:
org.eclipse.jface.operations包定义了一些接口用来在进度条下运行长时间的任务.
可以参见:
http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/jface_operations.htm

在eclipse插件和RCP开发中:
用户级别的job是互操作性最强的,它不仅能够让用户用Cancel键取消job,而且可以在Detail中展示具体情况,但是注意:
Detail只会在下面两种方法中出现:
IProgressService#busyCursorWhile或
IProgressService#runInUI
1)IProgressService#busyCursorWhile的用法例子:
注意这里的run()中做些和UI无关的事.
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
  progressService.busyCursorWhile(new IRunnableWithProgress(){
    public void run(IProgressMonitor monitor) {
      //do non-UI work
    }
  });

效果:

2)IProgressService#runInUI的用法例子:
注意这里的run()中可以做些和UI有关的事.
progressService.runInUI(
    PlatformUI.getWorkbench().getProgressService(),
    new IRunnableWithProgress() {
      public void run(IProgressMonitor monitor) {
        //do UI work
      }
    },
    Platform.getWorkspace().getRoot());

效果:

这里最后一个参数可以是null,或者是这个操作的规则,在这里我们是设定运行这个UI操作时锁定工作台.
更加具体的可以参见:
http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/workbench_jobs.htm

另外,有少数时候,我们不想弹出一个进度条窗口,而是只在最底下的状态栏显示就可以了,很简单,写自己的Job类时,在构造方法里加上一句:
setUser(false);就可以了.
2008 - 12 - 29

SWT 如何选中Spinner中所有的数字

关键字: spinner select all

http://dev.eclipse.org/newslists/news.eclipse.platform.swt/msg40029.html

 

            Spinner tempSpinner = new Spinner(parent, SWT.WRAP);
            tempSpinner.setLocation(10 ,10);
            tempSpinner.setSize(100, 20);
            tempSpinner.setMinimum(0);
            tempSpinner.setMaximum(12);

            tempSpinner.setSelection(6);
            tempSpinner.setFocus();

 

                  // tempSpinner如何实现Text类似SelectAll的功能呢?

 

			public void focusGained(FocusEvent e) {
				if(e.getSource() instanceof Spinner){
					Spinner spinner = (Spinner)e.getSource();
					int hwnd = OS.GetWindow (spinner.handle, OS.GW_CHILD);
					int hwndText = OS.GetWindow (hwnd, OS.GW_HWNDNEXT);
					OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
				}
			}

 

 

上面的就是解决方法, 难道非要去调用OS来通知Spinner进行全选吗?

 

2008 - 12 - 03

SWT 添加全局的监听

关键字: swt display filter listener

Display 有这么一个方法:

 

public void addFilter (int eventType, Listener listener)

 

具体使用代码:

       Display.getDefault().addFilter(SWT.KeyDown, new Listener() {

           public void handleEvent(Event e) {

              if ((e.stateMask == SWT.CTRL) && (e.keyCode == 'a')) {

                  System.out.println("XXXX");

              }

           }

       });

 

上面的代码给Display添加一个Filter, 这个Filter监听Ctrl+a事件.

 

 

也就是给Display添加一个全局的监听.比如:上面的就是快捷键Ctrl+a.

这个Display的Filter很强大, 无论当前焦点在哪个控件上,都可以监听这个Ctrl+a的事件.

 

如果界面中还有其他的控件也监听这个快捷键的话, 那么这个Display中的监听会比其他控件的监听先执行.

 

正由于Display的Filter比其他的监听先执行, 所以, 还更强大的功能就是: 你可以在handleEvent中阻拦event的向下传递[通知其他的监听者], 或者, 任意修改event的属性.

 

正由于Display的Filter这么强大和危险,慎用!

 

2008 - 11 - 23

SWT得到调用ActiveX所需的控件标识符

关键字: swt ole activex

怎么使用ole,网上别人的代码已经很多了. 下面是说怎么得到ole所需要的ActiveX标识符的方法.

[当然, 网上也有很多文章都是说通过查注册表.]

 

 

       OleFrame oleFrame = new OleFrame(shell, SWT.NONE); // 创建ActiveX控件的容器

       File file = new File("aa.pdf"); // 由于是.pdf文件,自己会弹出系统默认的AdobeReader.

       OleClientSite clientSite = new OleClientSite(oleFrame, SWT.NONE, file); // 创建一个ole嵌入面板

       clientSite.doVerb(OLE.OLEIVERB_SHOW);// 定义类型为显示控件

       System.out.println(clientSite.getProgramID()); // 得到ActiveX控件的唯一标识符

 

 

比如: 上面的代码得到的就是: AcroExch.Document.7

注: 由于我本地安装的是Adobe Reader

1.      

a)       ContentProposalAdapter

                         i.              内容建议Adapter类.

b)       IControlContentAdapter

                         i.              内容接口

c)       TextContentAdapter, ComboContentAdapter

                         i.              内容Adapter类 [专用于Text或Combo的].

                ii.              实现了IControlContentAdapter.

d)       SimpleContentProposalProvider

                         i.              建议Provider类.

e)       AutoCompleteField

                    i.              从ContentProposalAdapter和SimpleContentProposalProvider扩展出来的一个简易使用的类.

2.       Text

a)       提示内容: "aa", "BB", "无敌"

b)       输入一个a, 则自动弹出下面的shell, 并且将内容列表过滤后, 只出现以a开头的内容.

c)       不区分大小写, 无论输入'a'或'A', 效果都是一样的.

d)       代码:

                         i.              new AutoCompleteField(nameT, new TextContentAdapter(), new String[]{"aa", "BB", "无敌"});

 Text的效果图

 

3.       Combo

a)       提示内容: "BeiJing", "南京", "北京"

b)       代码:

                         i.              new AutoCompleteField(cityC, new ComboContentAdapter(), new String[] {"BeiJing", "南京", "北京"});

 Combo效果图

 

4.       更多自定义功能

a)       快捷键"Ctrl+1" 弹出提示.

b)       .或 空格 弹出提示.

c)       200毫秒弹出提示.

d)       代码:

       KeyStroke keyStroke = null; // null 表示不接受快捷键

       try {

           keyStroke = KeyStroke.getInstance("Ctrl+1"); // 在text上按Ctrl+1弹出popup的shell.

       } catch (Exception e) {

           e.printStackTrace();

       }

       ContentProposalAdapter adapter = new ContentProposalAdapter(remarksT, new TextContentAdapter(), new SimpleContentProposalProvider(new String[] {"one", "two", "three"}), keyStroke, new char[] {'.', ' '});

 更多自定义的效果图

 

5.       代码解释

a)       可以不用给ContentProposalAdapter指定LabelProvider. 如果指定,则不仅仅可以显示Text, 还可以显示Image.

b)       KeyStroke.getInstance("Ctrl+1").快捷键是Ctrl+1.

c)       ContentProposalAdapter.setAutoActivationDelay(200); 弹出popup的延迟时间.

d)       ContentProposalAdapter.setPropagateKeys(true);

                     i.              说明: 如果用户敲入的字母在内容列表内时,是否弹出popup内容列表.

                  ii.              true 弹出. 用户输入'o'会弹出popup的shell. 输入'.'或空格也会弹出.

              iii.              false 不弹出. 用户只有输入'.'或空格才弹出popup的shell. 输入'o'等,不弹出,即使'o'在内容中存在.

e)       ContentProposalAdapter.setFilterStyle(ContentProposalAdapter.FILTER_*);

                     i.              作用: 在用户敲入字母的时候是否过滤popup弹出的shell里面的内容.

                  ii.              ContentProposalAdapter.FILTER_NONE 不过滤. 说明: 下面的内容列表永远不变.

              iii.              ContentProposalAdapter.FILTER_CHARACTER 只用一个输入字符为条件过滤下面的内容列表. 说明:在输入多个字符后,下面的内容列表会被清空.

  • 描述: Text效果
  • 大小: 10 KB
  • 描述: Combo效果
  • 大小: 12.8 KB
  • 描述: 自定义效果
  • 大小: 13.5 KB
2008 - 11 - 06

SWT byte[]与Image的相互转换

关键字: image byte 转换
1. 从byte[]得到Image
	private static Image createImage(byte[] imageBytes) {
		Image image = null;
		try {
			ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
			image = new Image(null, bais);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return image;
	}


2. 从Image得到byte[]
	public static byte[] getImageBytes(Image image) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		ImageLoader imageLoader = new ImageLoader();
		imageLoader.data = new ImageData[] { image.getImageData() };
		imageLoader.save(baos, image.type);
		
		byte[] imageByteArray = baos.toByteArray();
		try {
			baos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return imageByteArray;
	}
2008 - 11 - 06

JFACE 用好StructuredViewer [可下载源代码] - 列表类型的动态控件创建

关键字: jface structuredviewer 动态控件
功能:
1. 类似一个TableViewer的功能.
2. 可添加一行
3. 可选择一行
4. 可删除选中的行

截图:
见附件:


源代码:
见附件.

运行:
RunApplication.java 右键 Run As -> Java Application

说明:
这个例子其实说的是: 动态控件操作.
通过StructuredViewer的使用, 使得操作完全忽略动态控件生成销毁等细节.
使用熟悉的StrucutredViewer的API.
比如: setInput, setSelection, getSelection等.

  • 描述: 预览图片
  • 大小: 14.7 KB
2008 - 11 - 03

AWT, SWING, SWT, JFACE 比较

关键字: awt swing swt jface
AWT
Abstract Windows Toolkit(AWT)是最原始的 Java GUI 工具包.在任何一个 Java 运行环境中都可以使用它.
AWT 是一个非常简单的具有有限 GUI 组件、布局管理器和事件的工具包.有些经常使用的组件,例如表、树、进度条等,都不支持.

通常对于 AWT 来说(也适用于 Swing 和 SWT),每个事件类型都有一个相关的 XxxListener 接口(XxxAdapter 的实现可能为空),其中 Xxx 是去掉 Event 后缀的事件名(例如,KeyEvent 事件的接口是 KeyListener),用来把事件传递给处理程序。应用程序会为自己感兴趣处理的事件的事件源(GUI 组件或部件)进行注册。有时监听接口要处理多个事件。

AWT 的一个很好的特性是它通常可以对 GUI 组件自动进行销毁。这意味着您几乎不需要对组件进行销毁。一个例外是高级组件,例如对话框和框架。如果您创建了耗费大量主机资源的资源,就需要手动对其进行销毁。

AWT 组件是 “线程安全的(thread-safe)”,这意味着我们不需要关心在应用程序中是哪一个线程对 GUI 进行了更新。这个特性可以减少很多 GUI 更新的问题,不过使 AWT GUI 运行的速度更慢了。

AWT 让我们可以以自顶向下(top-down) 或自底向上(bottom-up) 或以任意组合顺序来构建 GUI。自顶向下的意思是在创建子组件之前首先创建容器组件;自底向上的意思是在创建容器(或父)组件之前创建子组件。在后一种情况中,组件的存在并不依赖于父容器,其父容器可以随时改变。

由于 AWT 要依赖于主机 GUI 的对等体(peer)控件(其中每个 AWT 组件都有一个并行的主机控件或者对等体)来实现这个 GUI,这个 GUI 的外观和行为(这一点更重要)在不同的主机上会有所不同。这会导致出现 “编写一次随处测试(write once, test everywhere,即 WOTE)” 的情况,这样就远远不能满足我们的要求了。

AWT 提供了一个丰富的图形环境,尤其是在 Java V1.2 及其以后版本中更是如此。通过 Graphics2D 对象和 Java2D、Java3D 服务,我们可以创建很多功能强大的图形应用程序,例如画图和制表包;结合使用 JavaSound,我们还可以创建非常有竞争力的交互式游戏。


Swing
Java Swing 是 Java Foundation Classes(JFC)的一部分,它是试图解决 AWT 缺点的一个尝试。在 Swing 中,Sun 开发了一个经过仔细设计的、灵活而强大的 GUI 工具包。
Swing 是在 AWT 组件基础上构建的。

为了克服在不同主机上行为也会不同的缺点,Swing 将对主机控件的依赖性降至了最低。实际上,Swing 只为诸如窗口和框架之类的顶层 组件使用对等体。大部分组件(JComponent 及其子类)都是使用纯 Java 代码来模拟的。这意味着 Swing 天生就可以在所有主机之间很好地进行移植。因此,Swing 通常看起来并不像是本地程序。实际上,它有很多外观,有些模拟(尽管通常并不精确)不同主机的外观,有些则提供了独特的外观。

Swing 对基于对等体的组件使用的术语是重量级(heavyweight),对于模拟的组件使用的术语是轻量级(lightweight)。实际上,Swing 可以支持在一个 GUI 中混合使用重量级组件和轻量级组件,例如在一个 JContainer 中混合使用 AWT 和 Swing 控件,但是如果组件产生了重叠,就必须注意绘制这些控件的顺序。

Swing 无法充分利用硬件 GUI 加速器和专用主机 GUI 操作的优点。结果是 Swing 应用程序可能比本地 GUI 的程序运行速度都慢。Sun 花费了大量的精力来改进最近版本的 Swing (Java V1.4 和 1.5)的性能,这种缺点正在变得日益微弱。由于 Swing 的设计更加健壮,因此其代码基础也更坚实。这意味着它可以在一台健壮的机器上比 AWT 和 SWT 上运行得更好。

与 AWT 一样,Swing 可以支持 GUI 组件的自动销毁。Swing 还可以支持 AWT 的自底向上和自顶向下的构建方法。

与 AWT 不同,Swing 组件不是线程安全的,这意味着您需要关心在应用程序中是哪个线程在更新 GUI。如果在使用线程时出现了错误,就可能会出现不可预测的行为,包括用户界面故障。有一些工具可以帮助管理线程的问题。

与 AWT 类似,Swing 的一个优点是,它也是 Java 技术的一种标准配置。这意味着您不需要自己来安装它了。不幸的是,Swing 已经有了很大的变化,因此它很容易变得依赖于最新版本的 Java 语言所提供的特性,这可能会强制用户更新自己的 Java 运行时环境。


SWT
与 AWT 的概念相比,SWT 是一个低级的 GUI 工具包。JFace 是一组用来简化使用 SWT 构建 GUI 的增强组件和工具服务。SWT 的构建者从 AWT 和 Swing 实现中学习了很多经验,他们试图构建一个集二者优点于一体而没有二者的缺点的系统。从很多方面来说,他们已经成功了。

SWT 也是基于一个对等体实现的,在这一点上它与 AWT 非常类似。它克服了 AWT 所面临的 LCD 的问题,方法如下:定义了一组控件,它们可以用来构建大部分办公应用程序或开发者工具,然后可以按照逐个主机的原则,为特定主机所没有提供的控件创建模拟控件(这与 Swing 类似)。对于大部分现代主机来说,几乎所有的控件都是基于本地对等体的。这意味着基于 SWT 的 GUI 既具有主机外观,又具有主机的性能。这样就避免了使用 AWT 和 Swing 而引起的大部分问题。特定的主机具有一些低级功能控件,因此 SWT 提供了扩充(通常是模拟的)版本(通常使用 “C” 作为名字中的第一个字母),从而可以产生更一致的行为。

在对等体工作方式上,SWT 与 AWT 不同。在 SWT 中,对等体只是主机控件上的一些封装程序而已。在 AWT 中,对等体可以提供服务来最小化主机之间的差异(就是在这里,AWT 碰到了很多行为不一致的问题)。这意味着 SWT 应用程序实际上就是一个主机应用程序,它必然会全部继承主机的优点和缺点。这还意味着 SWT 不能完全实现 WORE 的目标;它更像是一种 WOTE 解决方案。这就是说,SWT 尽管不如 Swing 那么优秀,但是它在创建可移植解决方案方面是很杰出的。

SWT 不支持 GUI 控件的自动销毁。这意味着我们必须显式地销毁所创建的任何控件和资源,例如颜色和字体,而不能利用 API 调用来实现这种功能。这种工作从某种程度上来说得到了简化,因为容器控制了其子控件的自动销毁功能。

使用 SWT 只能自顶向下地构建 GUI。因此,如果没有父容器,子控件也就不存在了;通常父容器都不能在以后任意改变。这种方法不如 AWT/Swing 灵活。控件是在创建时被添加到父容器中的,在销毁时被从父容器中删除的。而且 SWT 对于 style 位的使用只会在构建时进行,这限制了有些 GUI 控件的灵活性。有些风格只是一些提示性的,它们在所有平台上的行为可能并不完全相同。

与 Swing 类似,SWT 组件也不是线程安全的,这意味着您必须要关心在应用程序中是哪个线程对 GUI 进行了更新。如果在使用线程时发生了错误,就会抛出异常。我认为这比不确定的 Swing 方法要好。有一些工具可以帮助管理线程的问题。

如果所支持的操作系统提供了可访问性服务,那么 SWT GUI 通常也就具有很好的可访问性。当默认信息不够时,SWT 为程序员提供了一个基本的 API 来指定可访问性信息。

SWT 提供了一个有限的图形环境。到目前为止,它对于 Java2D 和 Java3D 的支持还不怎么好。Eclipse 使用一个名为 Draw2D 的组件提供了另外一种单独的图形编辑框架(Graphical Editing Framework,GEF),它可以用来创建一些绘图应用程序,例如 UML 建模工具。不幸的是,GEF 难以单独(即在整个 Eclipse 环境之外)使用。

与 AWT 和 Swing 不同,SWT 和 JFace 并不是 Java 技术的标准配置。它们必须单独进行安装,这可以当作是 Eclipse 安装的一部分,也可以当作是单独的库进行安装。Eclipse 小组已经使它的安装变得非常简单,并且 SWT 可以与 Eclipse 分开单独运行。所需要的 Java 档案文件(JAR)和动态链接库(DLL)以及 UNIX® 和 Macintosh 上使用的类似库可以从 Eclipse Web 站点上单独下载。JFace 库需要您下载所有的 Eclipse 文件,并拷贝所需要的 JAR 文件。在下载所需要的文件之后,我们还需要将这些 JAR 文件放到 Java CLASSPATH 中,并将 DLL 文件放到系统 PATH 中。


SWT本身仅仅是Eclipse组织为了开发Eclipse IDE环境所编写的一组底层图形界面 API。或许是无心插柳,或是有意为之,至今为止,SWT无论是在性能和外观上,都超越了SUN公司提供的AWT和SWING。目前Eclipse IDE已经开发到了2.1版本,SWT已经十分稳定。这里指的稳定应该包含两层意思:

一是指性能上的稳定,其中的关键是源于SWT的设计理念。SWT最大化了操作系统的图形构件API,就是说只要操作系统提供了相应图形的构件,那么SWT只是简单应用JNI技术调用它们,只有那些操作系统中不提供的构件,SWT才自己去做一个模拟的实现。可以看出SWT的性能上的稳定大多时候取决于相应操作系统图形构件的稳定性。

另一个稳定是指SWT API包中的类、方法的名称和结构已经少有改变,程序员不用担心由于Eclipse组织开发进度很快(Eclipse IDE每天都会有一个Nightly版本的发布),而导致自己的程序代码变化过大。从一个版本的SWT更新至另一版本,通常只需要简单将SWT包换掉就可以了。

SWT采用了一种简单而直接的方式去适应本地GUI系统对线程的要求:在SWT中,通常存在一个被称为"用户线程"的唯一线程,只有在这个线程中才能调用对构件或某些图形API的访问操作。如果在非用户线程中程序直接调用这些访问操作,那么SWTExcepiton异常会被抛出。但是SWT也在*.widget.Display类中提供了两个方法可以间接的在非用户线程的进行图形构件的访问操作,这是通过的syncExec(Runnable)和asyncExec(Runnable)这两个方法去实现的。


JFace
JFace与SWT的关系好比Microsoft的MFC与SDK的关系,JFace是基于SWT开发,其API比SWT更加易于使用,但功能却没SWT来的直接。比如下面的代码应用JFace中的MessageDialog打开一个警告对话框:

MessageDialog.openWarning(parent," Warning"," Warning message");

如果只用SWT完成以上功能,语句不会少于30行!

JFace原本是为更加方便的使用SWT而编写的一组API,其主要目的是为了开发Eclipse IDE环境,而不是为了应用到其它的独立应用程序。因此在Eclipse 2.1版本之前,很难将JFace API完整的从Eclipse的内核API中剥离出来,总是要多多少少导入一些非JFace以外的Eclipse核心代码类或接口才能得到一个没有任何编译错误的JFace开发包。但目前Eclipse组织似乎已经逐渐意识到了JFace在开发独立应用程序起到的重要作用,在正在开发的2.1版本中,JFace也开始变成了和SWT一样的完整独立的开发包,只是这个开发包还在变动中(笔者写本文时,应用的Eclipse2.1M3版本)。JFace开发包的包前缀是以org.eclipse.jface开头。JAR包和源代码也和SWT一样,也在${你的eclipse安装路径}/plugins路径下去找。

对开发人员来说,在开发一个图形构件的时候,比较好的方式是先到JFace包去找一找,看是不是有更简洁的实现方法,如果没有再用SWT包去自己实现。比如JFace为对话框提供了很好的支持,除了各种类型的对话框(比如上面用的MessageDialog,或是带有Title栏的对话框),如要实现一个自定义的对话框也最好从JFace中的Dialog类继承,而不是从SWT中的*.widget.Dialog继承。

应用JFace中的Preference包中的类很容易为自己的软件做出一个很专业的配置对话框。对于Tree、Table等图形构件,它们在显示的同时也要和数据关联,例如Table中显示的数据,在JFace中的View包中为此类构件提供了Model-View方式的编程方法,这种方法使显示与数据分开,更加利于开发与维护。JFace中提供最多的功能就是对文本内容的处理。可以在org.eclipse.jface.text.*包中找到数十个与文本处理相关类。

2008 - 10 - 13

SWT StyledText试用 [可下载项目代码]

关键字: swt styledtext
效果图 和 源代码:
效果图


源代码 点击下载.
注: 代码在JDK1.5, Eclipse3.2 和 Eclipse3.4均可使用.
选择运行: TxtApplication.java 即可

关键代码:
字体:
StyleRange.font = Font;


粗体:
StyleRange.fontStyle = SWT.BOLD;


斜体:
StyleRange.fontStyle = SWT.ITALIC;


下划线:
StyleRange.underline = true;


删除:
StyleRange.strikeout = true;


前景色:
StyleRange.foreground = Color;


背景色:
StyleRange.background = Color;


上升:
StyleRange.rise = int;


左对齐:
StyledText.setLineAlignment(startLine, length, SWT.LEFT);


居中:
StyledText.setLineAlignment(startLine, length, SWT.CENTER);


右对齐:
StyledText.setLineAlignment(startLine, length, SWT.RIGHT);


拖拽:
		DropTarget dropTarget = new DropTarget(StyledText, DND.DROP_MOVE);
		dropTarget.setTransfer(new Transfer[] { ObjectTransfer.getInstance() });
		dropTarget.addDropListener(new DropTargetAdapter() {
			public void drop(DropTargetEvent event) {
				//...
			}
		});



相关资料:
Getting Your Feet Wet with the SWT StyledText Widget

Into the Deep End of the SWT StyledText Widget
  • 描述: StyledText的效果图
  • 大小: 41 KB
  • cn.iwoo.jface.rar (78.7 KB)
  • 描述: 源代码. 请选择TxtApplication.java进行运行.
  • 下载次数: 196
2008 - 09 - 05

Eclipse3.4 加速

关键字: eclipse3.4 加速 启动 慢

我的环境: eclipse-jee-ganymede-win32.zip.

这几天一直在捣腾环境, 被它害死了, 动不动整个Eclipse就白掉, 什么也用不了, 得了点心得. 贴下.

 

1. 加大Eclipse运行可用最大内存数

具体操作: 修改位于eclipse目录下的eclipse.ini, -Xmx512m调高, 我的改成了-Xmx768m
效果: 不祥
.

2.
减少Eclipse启动后自动启动的插件

具体操作: Preferences -> General -> StartUp and Shutdown:
Plug-ins activated on startup的项目不要的去掉, 很多Mylyn等我就没用到,去掉了
.

效果: 启动Eclipse,会有Initialing Java Tools的滚动条,会发现快了很多
.

3.
减少编译需要验证的项目,提升编译速度

    具体操作:
Preferences -> Validataion
    
将无关的Validator去掉, 比如: 我就将和我无关的JPA, JSP, WS 都去掉了
.

效果: 编译项目时,Eclipse跑的Validator项目少了, 确实快了
.

4.
关掉自动编译

    具体操作
: Project -> Build Automatically
效果: 在代码修改保存后,不会启动自动编译
.

5.
Clean的时候,要注意选项

    具体操作
: Project -> Clean
   
注意: 在最下面有
: Build the entire workspace
                   
Build Only the selected Projects
        
要根据自己情况勾选, 因为是默认选择编译整个工作区
.

6.
轻手轻脚

慢慢操作, 莫急, 机器卡住了耐心等就好.

 

7.其他

    如果Eclipse卡住了,并且处于最小化模式,点击WindowsEclipse的任务条再也无法使Eclipse最大化的时候,请在任务条上点击右键,使用最大化的菜单.


Eclipse工作正欢的时候,请不要去惊扰它,非要去操作界面的话,先用鼠标在你要点击的控件上试试,看看控件是否活着,否则不要去打扰它. 等吧.

目前也就这么点心得, Eclipse卡到闷死, 发现 轻手轻脚 才是王道...

 

2008 - 08 - 26

eclipse中任务进度的使用

关键字: job progress
1: 直接使用jFace提供的ProgressMonitorDialog
				ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell());

				IRunnableWithProgress runnable = new IRunnableWithProgress() {
					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
						monitor.beginTask("任务", 100);

						for (int i = 0; i < 10 && !monitor.isCanceled(); i++) {
							Thread.sleep(500);
							monitor.worked(10);
							monitor.subTask("第" + i + "个任务");
						}
						monitor.done();
					}
				};

				try {
					progressDialog.run(true,/*是否开辟另外一个线程*/
					true,/*是否可执行取消操作的线程*/
					runnable/*线程所执行的具体代码*/
					);
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

效果如下:


2. 使用Eclipse提供的job
				Job searchJob = new Job("Task") {
					protected IStatus run(IProgressMonitor monitor) {
						try {
							monitor.beginTask("", 100);

							for (int i = 0; i < 10; i++) {
								Thread.sleep(500);
								monitor.worked(10);
							}

							monitor.done();
						} catch (Exception e) {
							e.printStackTrace();
						}

						return Status.OK_STATUS;
					}
				};
				searchJob.setUser(true); // 是否需要弹出进度窗口
				searchJob.schedule();

效果如下[注意和上面的有一定区别]:


注: 第一段代码不知道从谁的blog中抄的, 版权归此君所有.
  • 描述: 使用Eclipse的job效果图
  • 大小: 30.1 KB
  • 大小: 29.6 KB
2008 - 06 - 03

惊艳!!! Swt 上的Ribbon.

关键字: swt ribbon
在Office2007中,大行其道的Fluent/Ribbon图形用户界面,真是漂亮.

今日在网上偶尔看到Swt上Ribbon. 真是惊艳呀.
主页:        http://www.hexapixel.com/projects/
Screenshots: http://www.hexapixel.com/ribbon/

可以下载它的jar包和源代码.
JAR
SOURCE


下面直接贴图:








2008 - 03 - 28

Swing,Swt开源Calendar的收集

文章分类:Web前端关键字: calendar
因为项目需要一个Calendar的控件,就上网找开源的Calendar了,将下面常见的做了一个统计.


    • nebula
    • Org.vafada.swtcalendar
    • com.gface.controls
    • net.sf.nachocalendar
    • JPopupCalendar



http://www.eclipse.org/nebula/
主页 http://www.eclipse.org/nebula/
这个是eclipse提供的一些基于swt的控件,至极的漂亮(不仅仅是Calendar).^-^. 网上有名的SwtPlus目前就是它的前身. 强烈推荐!!! Eclipse官方的,还是可以值得信赖的.




Org.vafada.swtcalendar
主页: http://swtcalendar.sourceforge.net/
Demo: http://swtcalendar.sourceforge.net/demos.html
简单,用的人蛮多的.


com.gface
主页: http://gface.sourceforge.net/
Demo: http://gface.sourceforge.net/jws/datepicker.jnlp
基于Swt的.配置性高.


net.sf.nachocalendar
主页: http://nachocalendar.sourceforge.net/
Demo: http://nachocalendar.sourceforge.net/demo/nachocalendar.jnlp
基于Swing的.


JPopupCalendar
主页: http://www.cwroethel.com/Projects/JPopupCalendar/
Demo: http://www.cwroethel.net/Projects/JPopupCalendar/webstart/popupcalendar/SimpleExample2.jnlp
最初的版本是基于Swing,目前已经有SWT的版本可供下载了.

2008 - 03 - 18

Eclipse内部属性事务机制

关键字: eventmanager
org.eclipse.core.commands.common.EventManager
public abstract class EventManager {
	private transient ListenerList listenerList = null;
    ...
}

在EventManager里面存储了所有的监听对象.

 
   protected void firePropertyChange(final int propertyId) {
        Object[] array = getListeners();
        for (int nX = 0; nX < array.length; nX++) {
            final IPropertyListener l = (IPropertyListener) array[nX];
            try {
                l.propertyChanged(WorkbenchPart.this, propertyId);
            } catch (RuntimeException e) {
                WorkbenchPlugin.log(e);
            }
        }
    }


在属性发生改变的时候,需要调用firePropertyChange()方法,该方法会遍历所有的监听,并调用监听的处理事件propertyChanged()方法.

public interface IPropertyListener {
    public void propertyChanged(Object source, int propId);
}

IPropertyListener就只有一个方法,表示,需要处理由特定属性propId的改变去做的响应.


在JavaBean中也有这个概念:
java.beans.PropertyChangeSupport {
addPropertyChangeListener();
firePropertyChange();
}



其实,这本来就是JavaBean的概念. JavaBean的传统应用领域就是UI领域.
而,目前,由于过多的Web UI的开发,使用的都是不带属性的组件.

具体的应用列子可以见:
不用线程实现更改ViewPart的TitleImage
http://lggege.javaeye.com/blog/173840

JavaBean组件,的属性分4类:
  •    简单类型, getter & setter & is
  •    索引类型, 指对一个数组的索引取值方法, 如 getValueFromArray(int index) {return this.valueArray[index]; }
  •    绑定类型, 就是PropertyChangeListener了, 就是UI领域应用最广.
  •    约束类型, 就是说 属性改变了,需要对这个属性改变监听的 认可,该属性才可以改变.     与绑定类型区别,就是,绑定是改变后通知,而, 这个是改变前通知,并可否决改变.

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开发项目用SWINGRCPSWT.JFACE的分析 第一个SWT程序 下面让我们开始一个SWT程序。(注意:以下的例子和说明主要针对Windows平台,其它的操作系统应该大同小异)。首先要在Eclipse安装文件中找到SWT包,Eclipse组织并不提供单独的SWT包下载,必须下载完整的Eclipse开发环境才能得到SWT包。SWT是作为Eclipse开发环境的一个插件形式存在,可以在${你的eclipse安装路径}\plugins路径下的众多子目录下去搜索SWT.JAR文件,在找到的JAR文件中包含了SWT全部的Java类文件。因为SWT应用了JNI技术,因此同时也要找到相对应的JNI本地化库文件,由于版本和操作平台的不同,本地化库文件的名称会有些差别,比如SWT-WIN32-2116.DLL是Window平台下Eclipse Build 2116的动态库,而在Unix平台相应版本的库文件的扩展名应该是.so,等等。注意的是,Eclipse是一个开放源代码的项目,因此你也可以在这些目录中找到SWT的源代码,相信这会对开发很有帮助。下面是一段打开空窗口的代码(只有main方法)。 import com.e2one.example; public class OpenShell{ public static void main(String [] args) { Display display = new Display(); Shell shell = new Shell(display); shell.open(); // 开始事件处理循环,直到用户关闭窗口 while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } } 确信在CLASSPATH中包括了SWT.JAR文件,先用Javac编译例子程序。编译无错后可运行java -Djava.library.path=${你的SWT本地库文件所在路径} com.e2one.example.OpenShell,比如SWT-WIN32-2116.DLL件所在的路径是C:\swtlib,运行的命令应该是java -Djava.library.path=c:\swtlib com.e2one.example.OpenShell。成功运行后,系统会打开了一个空的窗口。 剖析SWT API 下面再让我们进一步分析SWT API的组成。所有的SWT类都用org.eclipse.swt做为包的前缀,下面为了简化说明,我们用*号代表前缀org.eclipse.swt,比如*.widgets包,代表的是org.eclipse.swt.widgets包。 我们最常用的图形构件基本都被包括在*.widgets包中,比如Button,Combo,Text,Label,Sash,Table等等。其中两个最重要的构件当数Shell和Composite。Shell相当于应用程序的主窗口框架,上面的例子代码中就是应用Shell构件打开一个空窗口。Composite相当于SWING中的Panel对象,充当着构件容器的角色,当我们想在一个窗口中加入一些构件时,最好到使用Composite作为其它构件的容器,然后再去*.layout包找出一种合适的布局方式。SWT对构件的布局也采用了SWING或AWT中Layout和Layout Data结合的方式,在*.layout包中可以找到四种Layout和与它们相对应的布局结构对象(Layout Data)。在*.custom包中,包含了对一些基本图形构件的扩展,比如其中的CLabel,就是对标准Label构件的扩展,上面可以同时加入文字和图片,也可以加边框。StyledText是Text构件的扩展,它提供了丰富的文本功能,比如对某段文字的背景色、前景色或字体的设置。在*.custom包中也可找到一个新的StackLayout布局方式。 SWT对用户操作的响应,比如鼠标或键盘事件,也是采用了AWT和SWING中的Observer模式,在*.event包中可以找到事件监听的Listener接口和相应的事件对象,例如常用的鼠标事件监听接口MouseListener,MouseMoveListener和MouseTrackListener,及对应的事件对象MouseEvent。 *.graphics包中可以找到针对图片、光标、字体或绘图的API。比如可通过Image类调用系统中不同类型的图片文件。通过GC类实现对图片、构件或显示器的绘图功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值