SWT里的GridLayoutFactory和GridDataFactory布局

我写的SWT程序里用到layout的地方大部分都是GridLayout,今天才发现原来从eclipse 3.2开始就有了这两个方便使的类:GridLayoutFactory和GridDataFactory。特别是GridDataFactory,以前要用至少三行的代码:

GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
txtName.setLayoutData(gd);

现在用一行就可以了(稍微长点儿):

GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(txtName);

或者有些情况下更简单:

GridDataFactory.generate(txtName, 2, 1);

顺便提一句:eclipse.org上关于SWT的例子在http://www.eclipse.org/swt/snippets就有很多,而JFace的例子则可以在这个地址(2015/10/20更新,JFace Snippets)找到(或者从cvs里下载)。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2008/12/09/1350938.html

[Eclipse]实现内容助理(1. 自动完成)

在实际项目应用里,如果需要用户手动输入比较复杂的文本内容时可以考虑利用内容助理(Content Assistant)功能减轻用户负担,同时减低出错的机会。Jface的SourceViewer支持内容助理,这篇帖子里介绍一下如 何实现自动完成(Auto Completion)功能,即向用户提示接下来可能输入的内容。

//Create a new source viewer
sourceViewer = new SourceViewer(shell, null, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);

//Set a blank document
sourceViewer.setDocument(new Document(""));
sourceViewer.setEditable(true);

StyledText txtSource = sourceViewer.getTextWidget();
GridData gd = new GridData(GridData.FILL_BOTH);
txtSource.setLayoutData(gd);

自动完成功能一般在以下两种条件下弹出一个小窗口向用户提示当前可供选择的选项,一是用户按下指定的组合键时,二是用户输入了特定的字 符时,SourceViewer支持这两种触发方式。在程序里使用SourceViewer和使用一般控件没有很大的分别,只是SourceViewer 是StyledText的包装,所以一些操作要通过getTextWidget()完成,如下所示:

//Configure source viewer, add content assistant support
sourceViewer.configure(new SourceViewerConfiguration() {
    @Override
    public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
        ContentAssistant assistant = new ContentAssistant();
        IContentAssistProcessor cap = new MyContentAssistProcessor();
        assistant.setContentAssistProcessor(cap, IDocument.DEFAULT_CONTENT_TYPE);
        assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
        assistant.enableAutoActivation(true);
        return assistant;
    }
});

现在这个SourceViewer还不能弹出任何提示,因为我们还没有给它一个SourceViewerConfiguration,后者通过getContentAssistant()负责提供一个IContentAssistant的实现。下面的代码显示了如何为SourceViewer设置SourceViewerConfiguration,这个例子里不论当前文本框里是什么内容都弹出一样的提示选项,在实际应用里可以根据内容改变选项:

public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
    String content = viewer.getTextWidget().getText();

    try {

        //Demo options
        final String[] options = new String[] { "sum()", "count()", "sort()" };

        //Dynamically generate proposal
        ArrayList result = new ArrayList();
        for (int i = 0; i < options.length; i++) {
            CompletionProposal proposal = new CompletionProposal(options[i], offset, 0, options[i].length());
            result.add(proposal);
        }
        return (ICompletionProposal[]) result.toArray(new ICompletionProposal[result.size()]);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

public char[] getCompletionProposalAutoActivationCharacters() {
    return TRIGGER_TOKENS;
}

上面代码里,MyContentAssistProcessor是我们对IContentAssistant接口的实现,它里面与自动完成有关的是computeCompletionProposals()和getCompletionProposalAutoActivationCharacters()这两个方法,前者返回的结果数组将作为弹出提示窗口里的选项,后者返回的字符数组包含了可以触发弹出窗口的特殊字符。

最后,我们还要支持用户触发内容助理,这要求为SourceViewer添加一个监听器:

sourceViewer.appendVerifyKeyListener(new VerifyKeyListener() {
    public void verifyKey(VerifyEvent event) {
        // Check for Alt+/
        if (event.stateMask == SWT.ALT && event.character == '/') {
            // Check if source viewer is able to perform operation
            if (sourceViewer.canDoOperation(SourceViewer.CONTENTASSIST_PROPOSALS))
                // Perform operation
                sourceViewer.doOperation(SourceViewer.CONTENTASSIST_PROPOSALS);
            // Veto this key press to avoid further processing
            event.doit = false;
        }
    }
});

实现后的结果截图如下图所示,(示例代码下载):

file

参考链接

为 SWT 应用程序配备内容助理
FAQ How do I add Content Assist to my language editor?
Eclipse Help - Content Assist

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/09/28/908648.html

SWT的SelectionEvent.stateMask不起作用问题

通常理解stateMask的作用是标志事件发生时是否有Shift、Ctrl等键同时按下,但SWT里绝大多数Control都不支持这个标志,无论按下什么键,事件对象里的stateMask都是0(不信可以运行下面的代码)。更奇怪的是这个问题已经被提出3年多还没有解决,stateMask只对MenuItem有用,那要怎么实现对Button的Ctrl+Click检测呢?

import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class ButtonTest { public static void main(String[] args) {
  Display display = new Display();
  Shell shell = new Shell(display);
  shell.setLayout(new GridLayout());
  shell.setSize(200, 200); final Button button = new Button(shell, SWT.NONE);
  button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) {
    System.out.println(e.stateMask);//Always zero
 }
  });
  button.setText("Test");

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

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/08/28/873677.html

Eclipse 3.3里新TreeViewer给EMF应用程序带来的一个问题

以前在Eclipse 3.2里做的一个EMF应用程序,到3.3里发现一些TreeViewer里标签显示的格式不对,例如原来显示“Condition true”的,在3.3下可能显示“1”。调试了一下发现这些TreeViewer在为每个节点获得标签时,若相应的XXXItemProvider实现了ITableItemLableProvider(即应用程序里有TableViewer也用到这个XXXItemProvider)时,会调用getColumnText()而不是getText()来得到文本内容。

在Eclipse新闻组里搜到这个帖子讲的是同一件事(新闻组是遇到问题后第一反应),原因不在EMF,是Eclipse 3.3里对TreeViewer的实现有了变化,新的实现把原来的TreeViewer当成只有一列的特殊的TableViewer来对待,以致EMF也把TreeViewer当成了TableViewer,当然会去找getColumnText()了。解决的办法也不复杂,新闻组里那个帖子也提到了,我给帖到这方便大家参考吧。

/**
 * @Added
 * Solve a problem raised in jface 3.3 tree viewer
 * @see http://dev.eclipse.org/newslists/news.eclipse.tools.emf/msg25409.html
 *
 */
class WorkaroundAdapterFactoryLabelProvider extends AdapterFactoryLabelProvider {
    /**
    * @param adapterFactory
    */
    public WorkaroundAdapterFactoryLabelProvider(AdapterFactory adapterFactory) {
        super(adapterFactory);
    }

    @Override
    public Image getColumnImage(Object object, int columnIndex) {
        return super.getImage(object);
    }

    @Override
    public String getColumnText(Object object, int columnIndex) {
        return super.getText(object);
    }
}

有了上面这个类,然后把原来setLabelProvider()里的AdapterFactoryLabelProvider换成它就可以了。EMF以后的版本应该会解决这个问题。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/08/21/864579.html

继承PageBookView实现自己的“属性视图”

很多Eclipse应用程序在提供一个Editor的同时还提供一些View,这些View监视Editor的Selection,提供一些上下文相关的信息。Eclipse自带的PropertySheet(属性视图)就是这样一个例子,Outline(大纲视图)也是如此,从功能上看,不妨把这类用途的视图称为“广义的属性视图”。

以前我都是直接继承ViewPart来实现自己的属性视图的,但我发现要花不少功夫在处理View与Editor的协调上。例如当Editor被关闭时,View里的信息也应该隐藏,切换Editor时也需要进行处理,等等。最近看一个项目的代码时发现他们是继承org.eclipse.ui.part.PageBookView来实现同样功能的,就像PropertySheet所做的一样,效果很不错,而且需要自己写的代码量不是很多,因为PageBookView里已经帮助处理了以上提到的大部分功能。因此这里介绍一下使用PageBookView的方法供大家参考。

顾名思义,PageBookView是这样一种View,它就像一本书,里面可以容纳多个Page,但同一时间只给用户显示一个Page。PageBookView负责根据当前活动的WorkbenchPart切换到合适的Page,实际显示的内容主要由Page提供,这些Page一般是通过WorkbenchPart的getAdapter()方法提供的。

继承PageBookView实现自己的属性视图时,PageBookView子类的实现几乎是固定的,如果你的View与WorkbenchPart里的Selection有关(上下文敏感),则继承PageBookView的时候应顺便实现ISelectionListener,然后在init()方法里注册自己为WorkbenchPage的选择监听器,并在selectionChanged()方法里把事件转发给当前显示的Page,下面的代码是一个典型的上下文敏感的PageBookView子类:

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.IPage;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.part.MessagePage;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.part.PageBookView;

public class ExampleView extends PageBookView implements ISelectionListener{

    public ExampleView() {
    }

    @Override
    protected IPage createDefaultPage(PageBook book) {
        MessagePage page = new MessagePage();
        initPage(page);
        page.createControl(book);
        page.setMessage("An example view is not available.");
        return page;
    }

    @Override
    public void init(IViewSite site) throws PartInitException {
        super.init(site);
        site.getPage().addSelectionListener(this);
    }

    @Override
    public void dispose() {
        getSite().getPage().removeSelectionListener(this);
        super.dispose();
    }

    @Override
    protected PageRec doCreatePage(IWorkbenchPart part) {
        // Try to get a custom page
        Object obj = part.getAdapter(IExamplePage.class);
        if (obj instanceof IExamplePage) {
            IExamplePage page = (IExamplePage)obj;
            if (page instanceof IPageBookViewPage) 
                initPage((IPageBookViewPage)page);
            page.createControl(getPageBook());
            return new PageRec(part, page);
        }
        // Use the default page
        return null;
    }

    @Override
    protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) {
        IExamplePage page = (IExamplePage) pageRecord.page;
        page.dispose();
        pageRecord.dispose();
    }

    @Override
    protected IWorkbenchPart getBootstrapPart() {
        IWorkbenchPage page = getSite().getPage();
        if (page != null)
            return page.getActiveEditor();
        else
            return null;
    }

    @Override
    protected boolean isImportant(IWorkbenchPart part) {
        return (part instanceof IEditorPart);
    }

    @Override
    public void createPartControl(Composite parent) {
        super.createPartControl(parent);
    }

    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        // we ignore our own selection or null selection
        if (part == this || selection == null) {
            return;
        }

        // pass the selection to the page
        if (!(getCurrentPage() instanceof IExamplePage))
            return;
        IExamplePage page = (IExamplePage) getCurrentPage();
        if (page != null) {
            page.selectionChanged(part, selection);
        }
    }
}

在上面这个View里,createDefaultPage()方法创建的Page是当活动WorkbenchPart不是我们所关心类型时所显示的信息,由MessagePage实现;isImportant()规定了这个View对什么样的WorkbenchPart感兴趣,在上面的例子里是只处理IEditorPart,作为对照,Eclipse的PropertySheet对所有类型的WorkbenchPart都有兴趣,除了它自己;如果活动WorkbenchPart是"Important"的,并且通过它的getAdapter()方法能得到我们需要的Page,则这个Page会显示在这个View里,否则还将显示缺省的MessagePage。

现在来看一下怎样实现自己的Page。一般要先定义一个继承自IPage的接口,它的一个作用是给WorkbenchPart#getAdapter()方法作为参数以标识我们需要的Page类型,如果前面PageBookView子类已经实现了ISelectionListener则它多半也要实现此接口,如下所示:

import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.part.IPage;

public interface IExamplePage extends IPage, ISelectionListener{

}

然后是具体的Page类,这个类其实和以前我们实现ViewPart的代码很相似,它继承自org.eclipse.ui.part.Page并实现刚才定义的接口,最重要的当然就是createControl()方法,如果需要还有selectionChanged()方法:

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.part.Page;

/**
 * @author zhanghao
 *
 */
public class ExamplePage extends Page implements IExamplePage {

    Text txtName;

    public ExamplePage() {
        super();
    }

    @Override
    public void createControl(Composite parent) {
        //Create your autual view UI here
        txtName = new Text(parent, SWT.BORDER);
    }

    @Override
    public Control getControl() {
        return txtName;
    }

    @Override
    public void setFocus() {

    }

    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        String name = ; //Get information from selection
        txtName.setText(name);
    }
}

补充一点,每个Page具有独立的ActionBar,也就是说要为PageBookView添加菜单或工具条项应该在Page里完成,一般实现在init()方法里。

现在还差一个步骤没做,那就是要在WorkbenchPart的getAdapter()方法里对这个View做出反应(这要求WorkbenchPart可访问自定义的Page类),典型情况下我们用自己的Page接口作为参数,代码类似下面这样:

public Object getAdapter(Class type) {
    if (type == IExamplePage.class) {
        return new ExamplePage();
    }
    return super.getAdapter(type);
}

当然,和以前一样还是要在plugin.xml里注册这个View,以便使用者能够在Eclipse里通过Window->Show View菜单命令把它显示出来。

最后,和PropertySheet相比,这样的实现还有一个小缺陷,那就是第一次打开这个View的时候不能显示Editor里当前选择的信息,大家不妨试着解决这个问题。(提示:参考PropertySheet的partActivated()方法)

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/07/23/828850.html

[SWT]动态生成WizardPage

Eclipse的Wizard是由一系列WizardPage组成的。缺省情况下,WizardDialog在初始化的时候就会调用每个WizardPage的createControl()方法来布局这些WizardPage,这是为了方便决定WizardDialog窗口的大小。但如果某个WizardPage里的控件是需要动态生成的,例如,用户在Page1里输入一个整数n,Page2里要根据这个整数生成n个文本框,由于Page2的createControl()只有一次被调用的机会,并且在得到n之前就被WizardDialog调用过了,集中布局的方式就为生成Page2的界面带来了困难。

和问题的描述比起来,解决的方法简单很多,只要覆盖Wizard的createPageControls()方法让它什么都不要做就可以了:

@Override
public void createPageControls(Composite pageContainer) {
    //super.createPageControls(pageContainer);
}

理论上讲,这样做带来的问题将是WizardDialog的大小不一定能容纳所有的控件,但在实际应用中我还没遇到,只要动态生成的控件不要太多,或者使用滚动的方式容纳即可。

参考资料

http://dev.eclipse.org/newslists/news.eclipse.tools/msg02641.html

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/06/07/775314.html

将SWT包装成Eclipse Plugin需要修改的地方

把一个SWT程序包装到Eclipse里作为Plugin运行很容易,但有以下几点需要注意:

1、Eclipse的PDE Tools->Convert Projects to Plug-in Projects可生成Plugin工程需要的文件,注意原来在classpath里对swt.jar的引用应改为manifest.mf文件里对 org.eclipse.ui的依赖。

2、相对路径文件的使用,在SWT里用ClassLoader.getResourceAsStream()等方法引用的文件放在Plugin里会找不到,应改为

FileLocator.toFileURL(Platform.getBundle("plugin.id").getEntry("/images")).getFile();

或与其等效的方式。

3、对本地方法需要的静态链接库dll文件的引用,如果SWT程序是在启动参数里指定的,在Plugin里需要修改,可在系统环境变量里加到Path里。

4、SWT程序的入口类一般会被Editor或View等Plugin元素代替,要注意原来在入口类里初始化的变量也要改到Plugin里,特别是静态变量,正确初始化以防止NullPointerException。

5、必要的话,利用JFace等Plugin特性改写原来的SWT对话框、树、表格等元素,可使UI更具Plugin风格。

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

[Eclipse]通过TreeColumn实现“表格树”TableTree

Eclipse 3.1里deprecate了TableTree这个控件,与之对应的jface的TableTreeViewer虽然没有deprecate,但使用它会得到很多警告。在TableTreeViewer的第一列里是不能显示图标的,因为这个位置被+/-符号占用了,而且TableTree是显示不出 Tree的层次的,也就是没有缩进。

SWT 3.1里的Tree控件新支持了列的显示,是通过TreeColumn来实现的。在jface里则没有添加新的viewer,使用原先的TreeViewer即可支持,下面是一段例子代码,注意如果在windows里运行要修改一下setInput()这条语句的参数,例如改为setInput(new File("c:\\"))

import java.io.File;

import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeColumn;

public class TreeColumnTest {

    public void run(){
        final Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());

        final TreeViewer viewer = new TreeViewer(shell, SWT.FULL_SELECTION);
        viewer.getTree().setHeaderVisible(true);
        TreeColumn column = new TreeColumn(viewer.getTree(), SWT.LEFT);
        column.setText("Name");
        column.setWidth(200);
        column = new TreeColumn(viewer.getTree(), SWT.LEFT);
        column.setText("Size");
        column.setWidth(100);
        column = new TreeColumn(viewer.getTree(), SWT.LEFT);
        column.setText("Hidden");
        column.setWidth(100);
        viewer.setContentProvider(new MyTreeContenetProvider());
        viewer.setLabelProvider(new MyTableLableProvider());
        viewer.setInput(new File("/"));

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

    public static void main(String[] args) {
        new TreeColumnTest().run();
    }

    class MyTreeContenetProvider implements ITreeContentProvider{

        public Object[] getChildren(Object parentElement) {
            File file=(File)parentElement;
            if(file.isDirectory())
                return file.listFiles();
            else
                return null;
        }

        public Object getParent(Object element) {
            File file=(File)element;
            return file.getParentFile();
        }

        public boolean hasChildren(Object element) {
            File file=(File)element;
            return file.isDirectory()/*&&file.list().length>0*/;
        }

        public Object[] getElements(Object inputElement) {
            File file=(File)inputElement;
            return file.isDirectory()?file.listFiles():new Object[]{file};
        }

        public void dispose() {

        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

        }

    }

    class MyTableLableProvider implements ITableLabelProvider{

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            File file=(File)element;
            switch (columnIndex) {
            case 0:
                return file.getName();
            case 1:
                return ""+file.length();
            case 2:
                return ""+file.isHidden();
            default:
                return "";
            }
        }

        public void addListener(ILabelProviderListener listener) {

        }

        public void dispose() {

        }

        public boolean isLabelProperty(Object element, String property) {
            return false;
        }

        public void removeListener(ILabelProviderListener listener) {

        }

    }
}

下面是运行画面:

file

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2006/03/07/344853.html

给表格的单元格增加编辑功能(补充)

这一篇是对“给表格的单元格增加编辑功能”的补充,目的是让表格列显示Checkbox并允许单击改变选中状态,例子中的表格共有三列,其中后两列均需要显示为Checkbox。

步骤一,构造TableViewer;

final String[] columnNames = new String[] { "Project", "Must", "Must Not" };//columnNames在后面也要用到,所以专门定义为一个数组
TableColumn column = new TableColumn(tbv.getTable(), SWT.NONE);
column.setText(columnNames[0]);
tbv.setColumnProperties(columnNames);//给每个列指定一个字符串属性值
column.setWidth(200);
column = new TableColumn(tbv.getTable(), SWT.NONE);
column.setText(columnNames[1]);
column.setWidth(100);
column = new TableColumn(tbv.getTable(), SWT.NONE);
column.setText(columnNames[2]);
column.setWidth(100);
tbv.setContentProvider(...);
tbv.setLabelProvider(...);
tbv.setInput(...);

步骤二,定义CellEditor数组并指定给前面的TableViewer:

final CellEditor[] editors = new CellEditor[tbv.getTable().getColumnCount()];
//editors[0]保留为空,因为第一列不需要显示为Checkbox
editors[1] = new CheckboxCellEditor(tbv.getTable());
editors[2] = new CheckboxCellEditor(tbv.getTable());
tbv.setCellEditors(editors);

步骤三,定义TableViewer的CellModifier,作用是告诉表格如何改变对象的属性值,注意在modify()方法里参数element可能是org.eclipse.swt.widgets.Item类型,如果是这种情况要通过Item#getData()得到实际的对象:

tbv.setCellModifier(new ICellModifier() {
    public boolean canModify(Object element, String property) {
        return property.equals(columnNames[1]) || property.equals(columnNames[2]);
    }

    public Object getValue(Object element, String property) {
        PortfolioItem item = (PortfolioItem) element;
        if (property.equals(columnNames[1])) {
            return Boolean.valueOf(item.isMust());
        }
        if (property.equals(columnNames[2])) {
            return Boolean.valueOf(item.isMustNot());
        }
        return null;
    }

    public void modify(Object element, String property, Object value) {
        if (element instanceof Item)
            element = ((Item) element).getData();
        PortfolioItem item = (PortfolioItem) element;
        if (property.equals(columnNames[1])) {
            item.setMust(((Boolean) value).booleanValue());
        }
        if (property.equals(columnNames[2])) {
            item.setMustNot(((Boolean) value).booleanValue());
        }
    }
});

步骤四,这时单击表格可以改变选中状态了,但显示的是True/False(或其他在LableProvider里定义的内容),见图1,而非Checkbox控件选中/清空的样子。

file
图1 单击表格单元可改变T/F

解决的办法很简单,在LabelProvider里根据属性值True/False显示不同的图片即可,这两个图片可以在这里下载(鼠标右键另存为):

public Object getColumnImage(Object object, int columnIndex) {
    PortfolioItem item=(PortfolioItem)object;
    switch (columnIndex) {
    case 1:
        return item.isMust()?PortfolioEditPlugin.getPlugin().getImage("checked"):PortfolioEditPlugin.getPlugin().getImage("unchecked");
    case 2:
        return item.isMustNot()?PortfolioEditPlugin.getPlugin().getImage("checked"):PortfolioEditPlugin.getPlugin().getImage("unchecked");
    default:
        return null;
    }        
}

public String getColumnText(Object object, int columnIndex) {
    PortfolioItem item=(PortfolioItem)object;
    switch (columnIndex) {
    case 0:
        return item.getProject()==null?"N/A":item.getProject().getName();
//在显示为Checkbox的两列里不需要文字
//        case 1:
//            return item.isMust()?"True":"False";
//        case 2:
//            return item.isMustNot()?"True":"False";
    default:
        return "";
    }
}

最后是运行结果:

file

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2006/02/25/337367.html

SWT里Slider和Scale的区别

以前以为SliderScale之间只是外观的区别,今天发现不是这样的,因为Slider有一个特点:getSelection()能得到的最 大值并不是getMaximum()的值,要减去getThumb()值,后者是中间的滑块所拥有的值,缺省为10,最小为1。运行这个程序观察控制台的 输出。

import org.eclipse.swt.*;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.*;

public class SliderTest {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);

        //Slider
        final Slider slider = new Slider(shell, SWT.HORIZONTAL);
        slider.setBounds(10, 10, 200, 32);
        slider.setMinimum(0);
        slider.setMaximum(100);
        slider.setThumb(5);
        slider.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                System.out.println("Slider Selection:" + slider.getSelection());
            }
        });

        //Scale
        final Scale scale = new Scale(shell, SWT.HORIZONTAL);
        scale.setBounds(10, 50, 200, 72);
        scale.setMinimum(0);
        scale.setMaximum(100);
        scale.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                System.out.println("Scale Selection:" + scale.getSelection());
            }
        });

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

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/10/26/262517.html