给表格的单元格增加编辑功能(In place edit)

使用纯粹的SWT可以实现在单元格中编辑(In place edit)的功能,代码见这个例子,这里要说的是利用jface完成差不多的工作:用户单击单元格,出现一个下拉菜单,用户通过选择来改变单元格所代表的该行对象的属性。

对org.eclipse.jface.viewers.TableViewer.TableViewer的介绍这里就不赘述了,一般我们都是像下面这样定义TableViewer的:

TableViewer viewer = new TableViewer(...); 
viewer.getTable().setHeaderVisible(true); 
viewer.setContentProvider(...); 
viewer.setLabelProvider(...); 
//Add table columns 
TableColumn column = new TableColumn(viewer.getTable(), SWT.NONE); 
column.setText("..."); 

要增加编辑功能,首先得定义一个org.eclipse.jface.viewers.CellEditor数组,对应TableViewer的每一列,在我们这个例子里,第二列(Column 1)需要用下拉框编辑,所以可以这样定义这个CellEditor数组。

final CellEditor[] editors = new CellEditor[tvOre.getTable().getColumnCount()]; 
editors[1] = new ComboBoxCellEditor(viewer.getTable(), new String[] {}, SWT.READ_ONLY); 
viewer.setCellEditors(editors);
viewer.setColumnProperties(columnNames); 

再定义这个TableViewer的CellModifier(org.eclipse.jface.viewers.ICellModifier),该接口定义了三个方法,canModify()指出该单元格是否可被编辑;getValue()应返回单元格的当前值,因为我们使用的是下拉框,所以要返回一个Integer表示当前选中的index;modify()方法中我们将用户修改的值反映到实际模型中。代码如下,注意代码里IOre是我们模型的一部分,表格中每一行是一个IOre对象,IOre.getOrderParams()得到的就是下拉框中的选项,每行的选项与那一行代表的IOre对象有关:

viewer.setCellModifier(new ICellModifier() { 
    public boolean canModify(Object element, String property) { 
        IOre ore = (IOre) element; 
        String[] items = new String[ore.getOrderParams().size()]; 
        for (int i = 0; i < ore.getOrderParams().size(); i++) { 
            NameValuePair pair = (NameValuePair) ore.getOrderParams().get(i); 
            items[i] = pair.getValue(); 
        } 
        editors[1] = new ComboBoxCellEditor(viewer.getTable(), items, SWT.READ_ONLY); 
        return property.equals(columnNames[1]); 
    } 

    public Object getValue(Object element, String property) { 
        if (property.equals(columnNames[1])) { 
            IOre ore = (IOre) element; 
            for (int i = 0; i < ore.getOrderParams().size(); i++) { 
                NameValuePair pair = (NameValuePair) ore.getOrderParams().get(i); 
                if (pair.getValue().equals(ore.getOrderParamValue())) 
                    return new Integer(i); 
            } 
            return new Integer(0); 
        } 
        return null; 
    } 

    public void modify(Object element, String property, Object value) { 
        TableItem item = (TableItem) element; 
        IOre ore = (IOre) item.getData(); 
        NameValuePair pair = (NameValuePair) ore.getOrderParams().get(((Integer) value).intValue()); 
        ore.setOrderParamValue(pair.getValue()); 
        viewer.refresh(); 
    } 
}); 

接下来……哦,原来已经大功告成了,真是太容易了!不相信吗,请看下面的运行结果。

file

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/25/97336.html

SWT的GridData中一个需要注意的地方

如果在界面上有一个大文本框,一般我们会指定它的GridData为GridData.FILL_BOTH,这样在窗口改变大小时它的大小会随着变化。但在同一个GridLayout里,如果有多个这样的文本框,一定要注意它们的GridData中的grabExcessHorizontalSpace属性,该属性指出当一行中所有单元格的大小(宽/高)还不足以填充父控件时,是否增大其尺寸。

举一个具体的例子,有两行控件,父控件的Layout定义为new GridLayout(4,false),既有四列。第一行控件依次为Label0、Text1和Button2,其中Text3占2列;第二行为Text2,独占4列,我们希望第一行中的按钮右端和第二行中的文本框右端对齐,两个文本框都随窗口变宽而变宽,代码如下:

import org.eclipse.swt.*; 
import org.eclipse.swt.custom.*; 
import org.eclipse.swt.graphics.*; 
import org.eclipse.swt.layout.*; 
import org.eclipse.swt.widgets.*; 

public class MyLayout { 
    public static void main (String [] args) { 
        Display display = new Display (); 
        Shell shell = new Shell (display); 
        GridLayout gridLayout = new GridLayout (); 
        gridLayout.numColumns = 4; 
        shell.setLayout (gridLayout); 

        Label label0 = new Label (shell, SWT.NONE); 
        label0.setText ("label0"); 

        Text text1 = new Text (shell, SWT.BORDER); 
        text1.setText ("text1"); 
        GridData data = new GridData (); 
        data.horizontalAlignment = GridData.FILL; 
        data.horizontalSpan = 2; 
        data.grabExcessHorizontalSpace = true; 
        text1.setLayoutData (data); 

        Button button2 = new Button (shell, SWT.PUSH); 
        button2.setText ("button2"); 

        Text text3 = new Text (shell, SWT.BORDER); 
        text3.setText ("text3"); 
        data = new GridData (); 
        data.horizontalAlignment = GridData.FILL; 
        data.verticalAlignment = GridData.FILL; 
        data.horizontalSpan = 4; 
        data.grabExcessHorizontalSpace = true; //Wrong! 
        text3.setLayoutData (data); 

        shell.pack (); 
        shell.open (); 

        while (!shell.isDisposed ()) { 
            if (!display.readAndDispatch ()) 
                display.sleep (); 
        } 
        display.dispose (); 
    } 
}

因为想到两个文本框的宽度要变大,所以指定它们的GridData的grabExcessHorizontalSpace属性为true,而运行结果却与我们想的有差别。原因是下面的文本框实际上在宽度上占据了第一行中最靠两边的两个单元格,使得第一行中间的两个单元格宽度变小。为了解决这个问题,只要把定义第二个文本框Text3的grabExcessHorizontalSpace的语句去掉即可(缺省值为false)。

还需要注意,有时候为了简单起见,我们常使用GridData data=new GridData(GridData.FILL_BOTH)来定义GridData,这个FILL_BOTH上包含了FILL_HORIZONTAL和FILL_VERTICAL,而它们各自又包含了HORIZONTAL_ALIGN_FILL、GRAB_HORIZONTAL以及VERTICAL_ALIGN_FILL、GRAB_VERTICAL。所以,如果你是用构造方法定义的GridData,并且又希望不要grabExcessHorizontalSpace,则应该手动指定它为false才行。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/17/93269.html

给Eclipse插件的View加上菜单和工具条

Eclipse的每个视图(View)都有自己的菜单和工具条,View通过与自己相关的IViewSite对象与这些东西打交道,确切的说,是通过这个IViewSite对象的IActionBars对象来管理,ActionBars对象负责菜单、工具条和状态栏。

file

一个典型的View(继承org.eclipse.ui.part.ViewPart)的代码结构会是这样,作为例子,假设我们有三个功能项:Open、Remove和Reload,我们的View是一个简单的表格TableViewer,里面显示一些条目列表,允许用户进行多选:

TableViewer tvResult;
OpenAction openAction;
RemoveAction removeAction;
ReloadAction reloadAction;
public void createPartControl(Composite parent) {
    //创建视图界面

    //创建菜单
    createActions();
    createMenu();
    createContextMenu();
    createToolbar();
    hookGlobalActions();
}

其中,createActions()是创建必要的IAction对象,这些对象可用在菜单、工具条里;createMenu()的作用是把刚刚创建的IAction对象放进与View相关的MenuManager里,就像前面所说,MenuManager可以通过getViewSite().getActionBars().getMenuManager()方法得到;createToolbar()则是把同样的对象放在工具条里,获得工具条的方法与菜单类似;createContextMenu()则是建立鼠标右键触发的上下文菜单,方法是建立一个新的MenuManager,然后由它建立一个Menu对象,再将Menu对象与控件联系;hookGlobalActions()的作用是把IAction对象与系统菜单(而不是View菜单联系),达到同一菜单项对不同View具有不同响应的效果。下面来看一下具体代码:

package net.sf.solo.actions;

import java.io.IOException;
import java.util.Iterator;
import net.sf.solo.model.IInstance;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;

public class OpenAction extends Action implements ISelectionChangedListener {

    IStructuredSelection selection;

    public OpenAction() {
        setEnabled(false);
    }

    public void run() {
        for (Iterator iter = selection.iterator(); iter.hasNext();) {
            IInstance ins = (IInstance) iter.next();
            try {
                //TODO Only in windows can do this.
                Runtime.getRuntime().exec("cmd /E:ON /c start " + ins.getReferenceURL());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void selectionChanged(SelectionChangedEvent event) {
        selection = (IStructuredSelection) event.getSelection();
        setEnabled(selection.size() > 0);
    }

    public String getText() {
        return "&Open in browser";
    }
}

上面是一个例子IAction,它的作用是在触发时将用户选中的条目在浏览器里打开。这个类同时还实现了ISelectionChangeAction,这样就可以在用户没有选中任何条目的时候将自己变为不可用。当然,你要把它作为监听器加入某个列表对象的监听器列表,像下面代码里这样:

private void createActions() {
    openAction = new OpenAction();
    removeAction = new RemoveAction(tvResult);
    reloadAction = new ReloadAction(tvResult);
    tvResult.addSelectionChangedListener(openAction);
    tvResult.addSelectionChangedListener(removeAction);
    tvResult.addSelectionChangedListener(reloadAction);
}

注意,最后的三句就是加入监听列表的功能。有些IAction需要改变所监听对象(比如一个TableViewer)的行为,所以要把那个对象作为参数传递给它才行。下面是把IAction对象加入菜单的代码:

private void createMenu() {
    IMenuManager mgr = getViewSite().getActionBars().getMenuManager();
    mgr.add(openAction);
    mgr.add(removeAction);
    mgr.add(reloadAction);
}

把IAction对象加到工具条的代码几乎完全一样,只是第一句有所不同:

private void createMenu() {
    IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager();
    mgr.add(openAction);
    mgr.add(removeAction);
    mgr.add(reloadAction);
}

上下文菜单就显得有些麻烦了,因为View并没有一个“PopupMenuManager”这样的东西,所以我们只能半手动的来建立:

private void createContextMenu() {
    MenuManager mgr = new MenuManager();
    mgr.setRemoveAllWhenShown(true);
    mgr.addMenuListener(new IMenuListener() {
        public void menuAboutToShow(IMenuManager manager) {
            fillContextMenu(manager);
        }
    });
    Menu menu = mgr.createContextMenu(tvResult.getControl());
    tvResult.getControl().setMenu(menu);
    getSite().registerContextMenu(mgr, tvResult);
}

这个MenuManager和我们在createMenu()里通过getMenuManager()得到的是同一个类(但不是同一个实例哦),setRemoveAllWhenShown(true)的作用是清空以前显示的菜单项,当触发了menu事件时,重新填充(fillContextMenu),所以如果你不把removeAllWhenShow置为true的话,每点一下右键你就会看到菜单项多出一倍来。Menu是swt的控件(刚才说的MenuManager、ToolbarManager都是jface里的东西,jface给swt包了一层),用MenuManager可以创建出一个Menu对象,然后我们用表格的setMenu方法将表格控件与Menu控件联系在一起就好了。

最后还有一句,它是为扩展这个上下文菜单用的,例如你可以在plugin.xml里统一指定给某种类型的元素都加上某个菜单项(例如,如果用户选中了一个.zip文件,会多出一个“解压缩”选项)。那么新加的菜单项会出现在上下文菜单的哪里呢,最上方还是最下方,还是……?所以呢,要在fillContextMenu的时候指定一下:

protected void fillContextMenu(IMenuManager manager) {
    manager.add(openAction);
    manager.add(removeAction);
    manager.add(reloadAction);
    manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));

}

前三句都没什么特别,最后一句就是指定了上面我们说的这个“增加点”,这样,你想让后来的菜单放在哪里都行了。

最后,Eclipse的Workbench提供了一些比较通用的系统菜单项,如下:

public static final String [] GLOBAL_ACTIONS = {
        UNDO,
        REDO,
        CUT,
        COPY,
        PASTE,
        PRINT,
     DELETE,
        FIND,
     SELECT_ALL,
        BOOKMARK
};

当你的焦点在不同的View或Editor里时,同一个系统菜单项会有不同的作用产生。例如在文本编辑器中delete项是删除当前选中的文字,而在你的视图里,你希望delete的作用是删除用户选中的表格条目,刚好是removeAction的功能。所以你要把你的IAction对象和系统菜单挂在一起:

private void hookGlobalActions() {
      IActionBars bars = getViewSite().getActionBars();
      bars.setGlobalActionHandler(IWorkbenchActionConstants.DELETE, removeAction);
}

注意,要选择语义上比较相近的系统菜单项来挂接,否则会造成用户的困扰。比如你非要把COPY实现为openAction,当用户在系统菜单里选了copy命令,本以为会把当前选中的条目复制到剪贴板,你却给人家打开了这些条目,多滑稽。

好了,菜单方面基本上就这些内容。可以看出,Eclipse的Workbench的确为我们提供了很多方便,特别是如果能够灵活利用plugin来进行定义,不仅可以节约大量的代码,还能让我们始终保持对系统的掌握。所以说,RCP的风行可不是没有道理哦。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/14/92122.html

让URLConnection使用代理服务器

JDK的文档对使用代理服务器的介绍很少,据说JDK5.0好象增加了这方面的内容。其实要使用代理服务器很简单,只要在URL.openConnection()之前增加下面的代码即可:

Properties prop = System.getProperties(); 
prop.put("http.proxyHost", getProxyHost()); 
prop.put("http.proxyPort", "" + getProxyPort());

也就是给系统变量里增加了两个项,在执行程序时加上参数“-Dhttp.proxyHost=xxx”的效果也是一样的。

若代理服务器需要验证,则还要使用以下代码:

String authentication = getProxyUser() + ":" + getProxyPassword(); 
String encodedLogin = new sun.misc.BASE64Encoder().encodeBuffer(authentication.getBytes()); 
connection.setRequestProperty("Proxy-Authorization", "Basic " + encodedLogin);

也就是在Http头上增加了Proxy-Authorization信息。

更多属性:http://java.sun.com/j2se/1.4.2/docs/guide/net/properties.html

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/11/90236.html

[Eclipse]PreferencePage的小问题花了大把时间

在Eclipse里可以用FieldEditorPreferencePage简化Preference page的创建,但在随机文档里只重点说了要实现createFieldEditors方法,我明明实现了它,但点Preference命令时却总是提示:

java.lang.InstantiationException: org.haree.mobject.ui.BasicPreferencePage
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:141)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:124)
    at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:113)
    at org.eclipse.ui.internal.WorkbenchPlugin.createExtension(WorkbenchPlugin.java:189)
    at org.eclipse.ui.internal.dialogs.WorkbenchPreferenceNode.createPage(WorkbenchPreferenceNode.java:60)
    at org.eclipse.jface.preference.PreferenceDialog.showPage(PreferenceDialog.java:985)
    at org.eclipse.jface.preference.PreferenceDialog$8.selectionChanged(PreferenceDialog.java:529)
    at org.eclipse.jface.viewers.StructuredViewer$3.run(StructuredViewer.java:450)
    at org.eclipse.core.internal.runtime.InternalPlatform.run(InternalPlatform.java:616)
    at org.eclipse.core.runtime.Platform.run(Platform.java:747)
    at org.eclipse.jface.viewers.StructuredViewer.firePostSelectionChanged(StructuredViewer.java:448)
    at org.eclipse.jface.viewers.StructuredViewer.setSelection(StructuredViewer.java:1094)
    at org.eclipse.jface.preference.PreferenceDialog.selectSavedItem(PreferenceDialog.java:807)
    at org.eclipse.jface.preference.PreferenceDialog$3.run(PreferenceDialog.java:309)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:69)
    at org.eclipse.jface.preference.PreferenceDialog.createContents(PreferenceDialog.java:305)
    at org.eclipse.jface.window.Window.create(Window.java:348)
    at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:925)
    at org.eclipse.ui.internal.OpenPreferencesAction.run(OpenPreferencesAction.java:70)
    at org.eclipse.jface.action.Action.runWithEvent(Action.java:881)
    at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:915)
    at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:866)
    at org.eclipse.jface.action.ActionContributionItem$7.handleEvent(ActionContributionItem.java:785)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:82)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:796)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:2772)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2431)

找了一个多小时,才发现原来是要提供一个没有参数的构造方法才可以。想了一下,可能因为Eclipse最终是使用Class.newInstance()的方式来生成界面元素的,所以有这个要求。

算是一个经验吧,我觉得Eclipse的帮助再丰富些就好了,特别是应该提供更多的例子代码。

顺便推荐下面两篇文章(要是Eclipse帮助都这么详细该多好):

Mutatis mutandis - Using Preference Pages as Property Pages

Simplifying Preference Pages with Field Editors

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/11/90073.html

用正则表达式处理含中文字符串的问题

已经是第二次遇到同样的问题了,要匹配的字符串里含有中文,例如“<你好><Edward>”,我希望取出Edward的名字,所以正则表达式为“<[^>]><([^>])>”,匹配后只要取group(1)即可。在一台装有jdk1.4.2_06国际版的机器上,运行正常,但在装jdk1.4.2_01的机器上,则完全不能匹配。卸载原来的jdk,换成1.4.2_06版就没有问题了。

为什么会有这个区别呢,我试了增加各种参数例如-Duser.language=zh -Duser.region=cn -Dfile.encoding=GBK都没有用,难道我的程序要求用户机器上必须装最新的jdk1.4?但据我所知,还有很多机器上装的是jdk1.4.0呢,更别说jdk5.0了。

时间关系,这个问题暂时放在这里,欢迎提供解决方法。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/07/88414.html

在应用程序中利用Jena API处理OWL本体

接触Semantic Web的时间还不是很长,所以现在写的这方面内容算是笔记性质,很可能存在很多误解,欢迎指出或讨论:)

一般来说,我们在Protege这样的编辑器里构建了本体,就会想在应用程序里使用它,这就需要一些开发接口。用程序操作本体是很必要的,因为在很多情况下,我们要自动生成本体,靠人手通过Protege创建所有本体是不现实的。Jena是HP公司开发的这样一套API,似乎HP公司在本体这方面走得很靠前,其他大公司还在观望吗?

可以这样说,Jena对应用程序就像Protege对我们,我们使用Protege操作本体,应用程序则是使用Jena来做同样的工作,当然这些应用程序还是得由我们来编写。其实Protege本身也是在Jena的基础上开发的,你看如果Protege的console里报异常的话,多半会和Jena有关。最近出了一个Protege OWL API,相当于对Jena的包装,据说使用起来更方便,这个API就是Protege的OWL Plugin所使用的,相信作者经过OWL Plugin的开发以后,说这些话是有一定依据的。

题目是说用Jena处理OWL,其实Jena当然不只能处理OWL,就像Protege除了能处理OWL外还能处理RDF(S)一样。Jena最基本的使用是处理RDF(S),但毕竟OWL已经成为W3C的推荐标准,所以对它的支持也是大势所趋。

好了,现在来点实际的,怎样用Jena读我们用Protege创建的OWL本体呢,假设你有一个OWL本体文件(.owl),里面定义了动物类(http://www.zoo.com/ont/Animal,注意这并不是一个实际存在的URL,不要试图去访问它),并且它有一些实例,现在看如下代码:

OntModel m = ModelFactory.createOntologyModel();
File myFile = ...;
m.read(new FileInputStream(myFile), "");
ResIterator iter = m.listSubjectsWithProperty(RDF.type, m.getResource("http://www.zoo.com/ont/Animal"));
while (iter.hasNext()) {
    Resource animal = (Resource) iter.next();
    System.out.println(animal.getLocalName());
}

和操作RDF(S)不同,com.hp.hpl.jena.ontology.OntModel是专门处理本体(Ontology)的,它是com.hp.hpl.jena.rdf.model.Model的子接口,具有Model的全部功能,同时还有一些Model没有的功能,例如listClasses()、listObjectProperties(),因为只有在本体里才有“类”和“属性”的概念。

上面的代码很简单,从ModelFactory创建一个OntModel,从指定文件把模型读到内存里。再下面的代码是一个例子,作用是取出模型中所有Animal的实例(Individual,也叫个体),并打印它们的名称。要从OntModel里取实例,也可以用listIndividuals()方法,只不过你得在得到的实例中判断它们是不是Animal的实例,我觉得不如用上面这种简易查询的方式来得方便。

Jena里扩展了很多Iterator,比如ResIterator、StmtIterator和NodeIterator等等,刚开始用会觉得很别扭,好象还不如都用java标准的Iterator,不知道Jena的设计者是怎么考虑的。要熟练掌握还是得对整个Jena的API有全局掌握才好。

在循环里,我们得到的每个元素都是一个Resource,因为本体里的任何东西都是资源,不论你想得到Subject、Property还是Object,在Jena里实际得到的都是资源(Resource),在Jena里,Property是Resource的子接口,而Jena并没有Subject或Object接口。(注:在OWL本体中,Subject->Property->Object组成一个三元组,例如:张小刚->父亲->张大刚;或者:绵羊多利->rdf:type->动物,rdf:type是一个特殊的属性,表示前者是后者的实例)

暂时先写到这,关于在本体中引入其他本体和使用推理,下次继续。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/06/87598.html

利用winrar自动备份重要资料

每个人的电脑上都有很多有价值的资料,例如你写的论文、Outlook中的信件、IE收藏夹、FeedDemon中的rss链接等等,经常备份的重要性自不用多说,但怎样让备份变为轻松简单而不是繁重的劳动呢,我在网上查找了很多备份工具,发现它们要么很贵,要么存在各种缺陷(如不使用通用的压缩格式),后来发现其实只使用winrar就完全可以完成这个任务,而大部分人的电脑上都有这个压缩软件。

打开winrar的帮助主题,你会发现在winrar的命令行模式里可以指定很多参数,其格式为:

WinRAR  <command> -<switch1> -<switchN> <archive> <files> <@listfiles> <path_to_extract\>

利用winrar可以从列表文件中读取要压缩的文件/文件夹这个功能,我们可以创建一个列表文件如C:\backup.txt,在这个文件里写入需要备份的文件/文件夹路径,格式很简单,每个路径一行即可。然后创建一个快捷方式(或批处理文件),其命令为:

"C:\Program Files\WinRAR\WinRAR.exe" a C:\backup.rar @C:\backup.txt

要进行备份的时候只要执行这个命令即可,这样会在C:生成备份后的压缩文件,你最好把它转移到其他存储装置上。配合windows的计划任务,还可以进行定时自动备份。你还可以指定其他参数,例如加上-ibck可以让备份在后台执行,加上-t参数可以在压缩完成后验证等等,具体请参考winrar帮助主题。

这个方法的缺点是你必须自己找出那些需要备份的信息,有一些软件把信息存在注册表里不好备份,所以你可能需要在使用这种方式备份的同时手动备份注册表。不过很多专门用于备份的工具也是没有这个功能的。

Update:经验技巧

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/12/28/82975.html

安装了一个Eclipse 3.0

以前一直都在用Eclipse 2.1,现在因为有个插件只支持3.0所以下了个最新的版本,来说说我感觉到的几个变化吧:

  1. 界面华丽了很多,图标更像IDEA的风格,而且没感觉速度有什么降低;
  2. 可以用快捷键Ctrl+M最大化和还原Editor了,能节省我很多鼠标操作;
  3. 虽然缺省设置是自动补齐括号的,但似乎对大括号不起作用;
  4. 可以按两次Ctrl+O显示继承来的方法;
  5. 原先用来删除一行代码的Ctrl+E功能变成了呼出Editor下拉列表,好象和Ctrl+F6有点重复,现在删除一行代码的快捷键是Ctrl+D;
  6. 代码可以折叠,但我感觉作用不明显,因为利用原来提供的功能已经足够快速定位到任何代码了;
  7. 代码格式化的功能有所改进,对比较长的代码还能够格式化得比较好看;
  8. 自动生成Getter/Setter可以指定代码插入的位置;
  9. 重构改变量名的时候不必须先保存文件了,我记得在2.1会要求先保存;
  10. 解除注释不是Ctrl+\而是和注释一样Ctrl+/,我本来是喜欢这种方式的,现在已经被2.1带走了;另外好象2.1里没有/* */的注释方式?
  11. 从一个类里向另一个类里复制代码,会自动增加这些代码需要的imports,很贴心和实用的功能。

这些大部分都是JDT部分的改变,可能最大的不同还是在结构上,比如RCP支持等等。不过我目前只是把它当IDE来用,现在机器上两个版本都在,因为2.1已经很好了而且用了那么长时间,实在不忍心就这样扔掉,另外2.1的外观我也很喜欢,显得很专业,即使在3.0里我也是切换到显示方形Tab的模式。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/12/23/80887.html

[翻译]什么是OWL本体

译注:本文是对文档A Practical Guide To Building OWL Ontologies Using The Protege-OWL Plugin and CO-ODE Tools Edition 1.0第三章的翻译,并省略了其中的图片。Protégé是一个斯坦福大学开发的本体编辑器,为开放源码软件,具有优秀的设计和众多的插件,是目前使用最广泛的本体编辑器之一。

什么是OWL本体

  我们使用本体(Ontology)来获取某一领域的知识,本体描述该领域的概念,以及这些概念之间的关系。目前有很多种不同的本体语言,它们各有千秋,而W3C(World Wide Web Consortium)目前的最新标准是OWL。和Protégé一样,OWL让描述各种概念成为可能,与此同时,它还提供了其他很多功能。它具有更丰富的操作符——例如与、或和非;它立足于一个不同的逻辑模型(logical model),该模型能够更好的定义概念,可以用从简单概念构造出复杂的概念,不仅如此,该模型还允许你使用推理机(reasoner)来检查本体中的陈述(statement)和定义(definition)是否一致,或者判断出哪个概念更适合于哪个概念,从而帮你维护一个正确的本体等等,当允许一个类(Class)拥有多个父类的时候,这一点至关重要。

一、三类OWL

  可以把OWL分为三个子语言:OWL-Lite、OWL-DL和OWL-Full,主要的分类依据就是它们的表达能力。其中,OWL-Lite是表达能力最弱的子语言,OWL-Full具有最强的表达能力,而OWL-DL的表达能力则在它们之间。我们可以认为OWL-DL是OWL-Lite的扩展,而OWL-Full是OWL-DL的扩展。

1.1 OWL-Lite

  从语法上来说,OWL-Lite是三个之中最简单的一个,当你的本体中类的层次结构很简单,并且只有简单的约束(constraint)时适合使用它来描述本体。例如,在需要把一个已存在的辞典(thesauri)移植到另一个差不多简单的概念层次时,OWL-Lite可以做得又快又好。

1.2 OWL-DL

  和OWL-Lite相比,OWL-DL的表达能力要丰富许多,它的基础是描述逻辑(Description Logics,即DL的由来)。描述逻辑是一阶逻辑(First Order Logic)的一个可判定的变种(译注:不一定准确,原文decidable fragment),因此可以用来进行自动推理,计算机从而可以知道本体中的分类层次,以及本体中的各种概念是否一致。

1.3 OWL-Full

  OWL-Full是OWL的三种子语言中表达能力最强的一个,适合在那些需要非常强的表达能力,而不用太关心可判定性(decidability)或是计算完全性的场合下使用。不过也正是由于表达能力太强这个原因,用OWL-Full表示的本体是不能进行自动推理的。

二、该使用哪一种子语言

  首先,要想确切的知道这三种子语言之间的区别,请参考OWL Web本体语言概要。尽管有很多因素需要考虑以决定该使用它们中的哪一个,但这里是一些最简单常用的原则。

  • 对于OWL-Lite和OWL-DL,考虑OWL-Lite提供的那些简单构造子(construct)是否足以描述你的本体,若是使用OWL-Lite,否则使用OWL-DL。
  • 对于OWL-DL和OWL-Full,考虑在你的应用中,是自动推理比较重要还是高表达能力(例如是否需要元类来建模)更重要,如果是前者,请使用OWL-DL,否则该使用OWL-Full。

  Protégé的OWL插件在编辑OWL-Lite和OWL-DL的本体时不做区分,但可以在选项里选择以OWL-DL或是OWL-Full方式编辑本体。

三、OWL本体的组成

  OWL本体的组成与Protégé提供的本体相似,基本上,只是在对组成部分的称呼有一些分别。例如OWL有个体(Individual)、属性(Property)和类(Class),而Protégé则分别称它们为实例(Instance)、槽(Slot)和类(Class)。

3.1 个体(Individual)

  个体代表(领域中)我们实际感兴趣的那些对象,Protégé和OWL有一个重要的区别就是OWL不使用唯一命名假设(Unique Name Assumption,UNA),也就是说,两个不同的名称可以对应到同一个个体。例如“伊丽莎白女王”、“女王”和“伊丽莎白?温莎”可能都对应同一个人。在OWL里,你必须明确的表达个体之间是否为相同的,否则它们可能相同也可能不相同。

  注:个体(Individual)有时也被称作实例(Instance),个体相当于类的实例。

3.2 属性(Property)

  属性是个体之间的二元关系,也就是说,属性把两个个体连接在一起。例如,属性hasSibling可能会把Matthew和Gemma这两个个体连接起来,而属性hasChild会把Peter和Matthew这两个个体连接起来;属性可以有反向属性(Inverse),例如hasOwner的反向属性是isOwnedBy;属性也可以被限制为只能拥有一个值,即所谓的函数属性(functional);属性还可以是具有传递性(transitive)或是对称的(symmetric)。

  注:这里所说的属性即Protégé中槽(Slot)的概念,在描述逻辑中它们就是角色(Role),在UML等面向对象方法中它们就是关系(Relation),而在GRAIL等形式化表达中将它们称作特性(Attribute)。

3.3 类(Class)

  OWL中的类代表一些个体的集合,OWL使用形式化(数学的)的方法精确描述出该类中成员必须具有的条件,例如,领域中全部猫的个体都属于Cat类。类可以通过继承关系组成层次结构,子类是父类中的特殊情况,例如考虑Animal和Cat这两个类,Cat可以是Animal的一个子类(即Animal是Cat的父类),这就表示了:所有的猫都是动物,所有Cat类的成员都是Animal类的成员,如果你是猫那么你也是动物,Cat类被Animal类所包含,等等。OWL-DL的一个重要特征就是父类和子类之间的(包含)关系可以被推理机自动计算出来。

  注:概念(Concept)这个词有时被用来代替类,实际上,类是概念的一个具体表现。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/12/17/78368.html