`
Arizona
  • 浏览: 32247 次
  • 性别: Icon_minigender_2
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

JFace EditingSupport for Custom Tables

阅读更多

Stan Lee in Spider Man taught us that, "With great power there must also come -- great responsibility!"  I think about that quote when working on Eclipse plug-ins, only it changes in my head to read, "With great power there must also come -- great complexity!"  Eclipse provides the building blocks to do wonderfully powerful things, but to wade into plug-in development is to wade into all sorts of complexity. 

My most recent responsibility/complexity was to make a service properties chooser/editor in the BUG Application code generation wizard.  This functionality (still in development at the time of this writing), will allow BUG Application developers tighter control of the filters used by the Application's Service Tracker.

Service property values are stored as strings, but they can represent booleans, numbers, or Strings.  I wanted to create a table where each row is a service property key/value pair.  The developer can then choose the properties they want to include in the filter and modify the values for that property.  Moreover, I wanted the property value to be editable like a text field for things like numbers, but use a combo box for things like boolean values.  Here's what the table looks like:

created on: 07/21/09

It looks straight forward enough, but the implementation turned out to be rather challenging.  The custom behavior of the cells pushed me toward using JFace CellEditorS and EditingSupport.  I found some tutorials and code-snippets on-line, but nothing suited my specific needs, which were to have checkbox support and selection events on the rows, plus different CellEditorS for each of the second column's cells, depending on the type of value.  The most helpful tutorial I found is here: http://www.vogella.de/articles/EclipseJFaceTable/article.html .  It didn't solve all my problems, but it certainly gave me a start.

After some time-consuming web-slinging, pining over the above tutorial, and some old-fashion trial and error, I was able to finally make the thing work.  Here, I share my solution in the hope that it will help where other resources fall short:

First, let's start out with the class.  This particular JFace component was added to a WizardPage:

public class CodeGenerationPage extends WizardPage {

 Next, define our main TableViewer as an instance variable:

// Main JFace component
private CheckboxTableViewer servicePropertiesViewer;

 All of the wizard page drawing is kicked off from the createControl method, which you must override.  Inside there, we create the JFace components -- a CheckboxTableViewer which is the surrounding table, and TableColumnViewerS for the columns -- and put it all together:

// table with list of properties to choose from
// compServices is a Group that we're putting  all of this stuff in
final Table propertiesTable = new Table(
        compServices, SWT.CHECK | SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION);
propertiesTable.setHeaderVisible(true);
propertiesTable.setLinesVisible(true);
// layout of columns in table
TableLayout propTableLayout = new TableLayout();
propTableLayout.addColumnData(new ColumnWeightData(90));
propTableLayout.addColumnData(new ColumnWeightData(120));
propertiesTable.setLayout(propTableLayout);

// layout of table on the page
GridData pViewerData = new GridData(GridData.FILL_BOTH);
pViewerData.horizontalSpan = layout.numColumns;  
pViewerData.heightHint = SERVICE_PROPERTIES_HEIGHT_HINT;
propertiesTable.setLayoutData(pViewerData);

// viewer for services list
servicePropertiesViewer = new CheckboxTableViewer(propertiesTable);
servicePropertiesViewer.setContentProvider(new ServicePropsContentProvider());

// Add a listener to do something when a checkbox on a row is selected
servicePropertiesViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
        // You can do something when a row is selected here
    }
});

// Column 0 - checkbox and property name
// col0 is taken care of by checkboxtableviewer
TableViewerColumn col0viewer =
    new TableViewerColumn(servicePropertiesViewer, SWT.FULL_SELECTION, 0);
// TableViewerColumn needs a label provider
col0viewer.setLabelProvider(new ColumnLabelProvider() {
    @Override
    public String getText(Object element) {
        return ((ServicePropertyHelper) element).getKey();
    }
});
col0viewer.getColumn().setText(KEY_LABEL);

// Column 1 - property value w/ celleditors
// col1 has custom cell editors defined in EditingSupport below
TableViewerColumn col1viewer =
    new TableViewerColumn(servicePropertiesViewer, SWT.FULL_SELECTION, 1);
col1viewer.setLabelProvider(new ColumnLabelProvider() {
    @Override
    public String getText(Object element) {
        return ((ServicePropertyHelper) element).getSelectedValue();
    }
});
col1viewer.getColumn().setText(VALUE_LABEL);
// col1viewer has editing support
// this is where the magic happens that sets a different celleditor depending
col1viewer.setEditingSupport(
        new PropertyValueEditingSupport(col1viewer.getViewer()));

 The comments in the code should help explain things, but there are two items worthy of extra attention.  First, by using a CheckboxTableViewer, we can get a selection event from the table and also access selected elements via servicePropertiesViewer.getCheckedElements().  For the second column's CellEditorS, we need to decide, per-cell, which editor to use (whether to use a TextCellEditor or a ComboBoxCellEditor) based on what the potential values are.  We do this by adding EditingSupport to the column, i.e. col1viewer.setEditingSupport().  Here is most of the EditingSupport implementation (with all the helper functions stripped out for brevity):

public class PropertyValueEditingSupport extends EditingSupport {

    private final String[] truefalse = new String[] {"true", "false"};
    private Composite parent;
    private TextCellEditor text_editor;
    private ComboBoxCellEditor combobox_editor;

    public PropertyValueEditingSupport(ColumnViewer viewer) {
        super(viewer);
        parent =((TableViewer) viewer).getTable();
        text_editor = new TextCellEditor(parent);
        combobox_editor = new ComboBoxCellEditor(parent, new String[0]);
    }

    @Override
    protected boolean canEdit(Object element) {
        return true;
    }
   
    @Override
    protected CellEditor getCellEditor(Object element) {
        ServicePropertyHelper propertyHelper = ((ServicePropertyHelper) element);

        if (usesTextEditor(propertyHelper.getValues())) {
            // Ints and blanks use text editor
            return text_editor;
        } else {
            // everything else uses a combobox
            if (hasBools(propertyHelper.getValues()))
                // boolean combos prefill w/ true and false
                combobox_editor.setItems(truefalse);
            else
                // other types, just do set the combobox to values
                 combobox_editor.setItems(propertyHelper.getValuesAsArray());
            return combobox_editor;
        }
    }
   
    @Override
    protected Object getValue(Object element) {
        ServicePropertyHelper propertyHelper = ((ServicePropertyHelper) element);

        if (usesTextEditor(propertyHelper.getValues())) {
           return propertyHelper.getSelectedValue(); 
        } else {
            return Integer.valueOf(propertyHelper.getSelectedIndex());
        }
    }
  
    @Override
    protected void setValue(Object element, Object value) { 
        // Get the current service that's been selected

        ServicePropertyHelper propertyHelper = ((ServicePropertyHelper) element);
   
        if (usesTextEditor(propertyHelper.getValues())) {
            // if it's a text field, just set the value
           propertyHelper.setSelectedValue("" + value);

       } else if (hasBools(propertyHelper.getValues())) {
           // if it's a boolean, value is an index in truefalse array
            propertyHelper.setSelectedValue(truefalse[Integer.valueOf("" + value)]);

        } else {
            // if it's something else, value is an index in the service property values set
            String val = propertyHelper.getValueAt(Integer.valueOf("" + value));
            if (val != null) propertyHelper.setSelectedValue(val);
        }
      
        getViewer().update(element, null);
    }
}  

In the constructor, we create our two CellEditorS.  We then override getCellEditor(Object element) to return the proper cell editor for the passed element.  Element is an element in the array returned from servicePropertiesViewer's ContentProvider.getElements() method (I must point out that the relationship between a TableViewer, it's ContentProvider, it's TableViewerColumnS, and a TableViewerColumn's EditingSupport is pretty confusing.  The tutorial mentioned above should help clear all that up if you're lost.  Also, if you're still in the dark about JFace viewers, label providers, content providers, and inputs, Eclipse: Building Commercial-Quality Plug-ins is a must-read).  We must also override a couple of other EditingSupport methods: canEdit(), getValue(Object element), and setValue(Object element, Object value).  The important thing to note is that the values (given and returned) for a TextCellEditor are Strings, and for a ComboBoxCellEditor, Integers.  My model object (when I set up my CheckBoxTableViewer, a list of model objects is set with the setInput() method), is called ServicePropertyHelper.  It keeps track of the possible values and the set/selected values for a property.  It also has some helper methods for setting these, which the PropertyValueEditingSupport methods call.

So, this is obviously rather complex stuff, but it's powerful as well.  Using EditingSupport and CellEditorS gives very fine-grained control over JFace TableViewerS for doing real custom Interfaces.  Lastly, the full classes can be found in our svn tree at svn://svn.buglabs.net/dragonfly/trunk/com.buglabs.dragonfly.ui/src/com/buglabs/dragonfly/ui/wizards/bugProject   and I'll be happy to answer any questions I can if you find yourself wrangling with similar problems.


 

  


  
分享到:
评论

相关推荐

    swt/jface.jar

    标题中的"swt/jface.jar"是一个关键组件,它在Java开发环境中用于构建用户界面。SWT(Standard Widget Toolkit)是IBM开发的一个开源GUI库,它提供了与原生操作系统更紧密集成的图形用户界面控件。JFace是建立在SWT...

    JFace教程

    ### JFace教程知识点详解 #### 一、JFace简介与应用场景 **JFace** 是 Eclipse 平台的一个重要组成部分,它提供了一套丰富的 API 来帮助开发者构建基于 SWT(Standard Widget Toolkit)的用户界面。JFace 的核心...

    SWT/JFace专题 --- SWT/JFace概述

    SWT (Standard Widget Toolkit) 和 JFace 是两个在Java中用于构建图形用户界面(GUI)的重要库,尤其在开发Eclipse插件时被广泛应用。它们是开源项目,由Eclipse基金会维护,为开发者提供了丰富的控件和高级UI设计...

    JFace 类包(3.14)

    JFace 是一个面向Java开发者的图形用户界面(GUI)构建框架,它建立在SWT(Standard Widget Toolkit)之上,提供了一种更高层次的抽象来创建应用程序的用户界面。JFace的目标是简化GUI开发,使开发者可以更加关注...

    SWT_JFace_in_action_jface_action_

    《SWT_JFace_in_Action》是一本专注于Java编程领域中SWT(Standard Widget Toolkit)和JFace技术的实践指南。这本书深入浅出地讲解了如何使用这两项强大的工具来构建功能丰富的图形用户界面(GUI)。SWT是Eclipse...

    mysource-jface

    "mysource-jface"是一个与Java编程相关的项目,主要涉及JFace库的使用。JFace是Eclipse框架的一部分,它提供了一组高级图形用户界面(GUI)组件和工具,简化了SWT(Standard Widget Toolkit)的使用。这篇博客文章...

    swt-jface入门

    【SWT/JFace 简介】 SWT(Standard Widget Toolkit)是Java开发者用于创建图形用户界面(GUI)的一种库,它与底层操作系统紧密集成,提供了可移植的API。SWT的优势在于其高性能和与操作系统原生界面的接近,这使得用...

    jface源代码不容错过

    在这个目录下,你可能会找到JFace的各个子模块,如视图(views)、对话框(dialogs)、表(tables)、树(trees)等组件的实现,以及事件处理和数据模型的相关类。 通过深入分析这些源代码,开发者可以学到以下几点...

    JFace一些资料

    **JFace技术详解** JFace是Eclipse框架中的一部分,它是构建用户界面(UI)的一种高级工具包。JFace的设计目标是提供一个面向对象的、与操作系统无关的接口,简化Swing和SWT(Standard Widget Toolkit)之间的开发...

    SWT/JFace从入门到精通

    【SWT/JFace从入门到精通】 SWT(Standard Widget Toolkit)和JFace是Eclipse平台下用于构建图形用户界面(GUI)的两个关键库。它们为Java开发者提供了丰富的控件和高级UI功能,使创建桌面应用程序变得简单而强大。...

    Eclipse SWT JFace核心应用_pdf_含标签_目录

    《Eclipse SWT/Jface核心应用》全面介绍了SWT、JFace和RCP的相关知识。全书共分5篇,第1篇介绍了SWT产生的背景以及SWT的一些基本概念和基础知识。第2篇介绍了SWT基本控件的使用,以及事件处理、布局等SWT基本知识的...

    JFace TableViewer的单元格逐个遍历的辅助类

    Since 3.3, an alternative API is available, see ViewerColumn.setEditingSupport(EditingSupport) for a more flexible way of editing values in a column viewer. 从3.3开始,tableViewer.setCellEditors...

    SWT + JFace 入门

    SWT (Standard Widget Toolkit) 和 JFace 是两个用于构建Java图形用户界面(GUI)的开源库,它们在Java开发中特别是在开发桌面应用时扮演着重要角色。本文将深入探讨这两个库,以及如何入门使用它们。 SWT是IBM开发...

    Eclipse SWT/Jface环境设置 DOC文件

    Eclipse SWT(Standard Widget Toolkit)和JFace是Java开发中用于构建图形用户界面(GUI)的库,尤其在开发Eclipse插件或RCP(Rich Client Platform)应用时非常常见。SWT是Eclipse项目的一个核心组件,它提供了一套...

    全面介绍SWT-JFace

    JFace是建立在SWT之上的更高层次的抽象框架,简化了GUI开发的复杂性,使得代码更简洁,结构更清晰。 SWT的设计目标是提供与本机系统更紧密的集成,因此它能够创建出与平台原生应用类似的外观和行为。这与Java Swing...

    swt_jface_celleditor

    在Java编程领域, SWT (Standard Widget Toolkit) 和 JFace 是两个强大的图形用户界面(GUI)库,它们被广泛用于构建桌面应用程序。`swt_jface_celleditor` 标题和描述所涉及的知识点主要围绕如何在SWT/JFace中的...

    使用 JFace 工具箱.pdf清晰版

    ### 使用JFace工具箱的关键知识点 #### 一、JFace工具箱概述 - **定义**:JFace作为Eclipse项目的一部分,提供了一系列高级且易于使用的用户界面组件,这些组件能够帮助开发者快速构建复杂的图形用户界面(GUI)...

    SWT/JFACE API

    SWT (Standard Widget Toolkit) 和 JFace 是两个用于构建Java图形用户界面(GUI)的开源库,它们在Java开发领域中被广泛使用,特别是在Eclipse IDE及其插件开发中。SWT是底层的UI库,提供了与操作系统原生控件直接...

    swt/jface api帮助文档

    SWT (Standard Widget Toolkit) 和 JFace 是两个与Java GUI编程密切相关的库,它们是Eclipse项目的一部分。本文将深入探讨这两个库的核心概念、功能以及API的使用。 SWT是Java的一个GUI(图形用户界面)工具包,它...

Global site tag (gtag.js) - Google Analytics