试用Google Web Toolkit(2)

把GWT中sample目录中的KitchenSink按(1)中的步骤建立一个eclipse工程


projectCreator -eclipse KitchenSink
applicationCreator -eclipse KitchenSink com.google.gwt.sample.kitchensink.client. KitchenSink

在把sample/KitchenSink/com/.../kitchensink目录下的client和public拷贝过来,这个工程实际上演示GWT中的主要UI组件。

在GWT中如果想要创造一个复杂组件,你需要从Composite类派生一个子类,在这个子类中,你可以封装一系列其他从Widget派生的组件,对外提供一致的抽象接口。

比如,我想写一个类似于一般IDE中都提供的属性编辑器,很显然,这个东西由多个属性编辑项(Item)构成,而每个属性项目包括属性的名字以及他对应的值,这个值可以由Text, Combox, List, Dialog等等你能想到的一切能输入值的组件构成。

首先来看看我们的基本单位PropertyItem(属性项)应该是个什么样子。

package com.google.gwt.sample.kitchensink.client.custom;
// 从Composite 继承,组合两个组件属性名字和属性值
public class PropertyItem extends Composite {
    // 用id来唯一标识每个item
    private String id;  
    // 属性的名字,选择用Label或是HTML控件
    private HTML nameView;
    // 属性值的编辑器
    private BaseEditor valueView;
    // panel,放置属性名字和属性值的容器组件,这是一个横向排列的panel
    private HorizontalPanel container = new HorizontalPanel();
}

最大的麻烦恐怕就是属性值的编辑器了,因为它可以是一个任何可能的编辑器,考虑把它抽象为一个接口;

package com.google.gwt.sample.kitchensink.client.custom;

import com.google.gwt.user.client.ui.Widget;

public interface Editable {
    // 一个属性值编辑器必须能取值和设置值,当然这个值对象可能更复杂一些,不过先用一个String类就够了
    public String getValue();
    public void setValue(String value);
    // 这个编辑器需要暴露它的最高层的UI组件,以便显示在PropertyItem中。
    public Widget getWidget();
}


接下来要考虑的事情是:在属性值的编辑器的值发生变化时,外部可以接收到值变化的事件。
package com.google.gwt.sample.kitchensink.client.custom;
public interface ChangeListener {
    public void onChange(Editable sender);
}

每个属性值编辑器都是一个事件源,需要提供注册事件捕捉器的能力。
package com.google.gwt.sample.kitchensink.client.custom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class BaseEditor implements Editable {

    private List listeners = new ArrayList();
   
    public BaseEditor() {
    }
   
    public boolean addChangeListener(ChangeListener listener) {
        return listeners.add(listener);
    }
   
    public boolean removeChangeListener(ChangeListener listener) {
        return listeners.remove(listener);
    }
   
    public ChangeListener removeChangeListener(int index) {
        return (ChangeListener)listeners.remove(index);
    }
   
    public void notifyAllChangeListeners() {
        for (Iterator iter= listeners.iterator(); iter.hasNext();) {
            ((ChangeListener)iter.next()).onChange(this);
        }
    }
       
}


看看如何实现一个基本的属性编辑器,比如一个最普通的文本输入框,它只是对TextBox组件一个adaptor。
package com.google.gwt.sample.kitchensink.client.custom;

import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class TextEditor extends BaseEditor implements com.google.gwt.user.client.ui.ChangeListener  {

    private TextBox editor = new TextBox();
   
    public TextEditor() {
        super();
        editor.addChangeListener(this);
    }

    public String getValue() {
        return editor.getText();
    }

    public void setValue(String value) {
        editor.setText(value);
    }

    public void onChange(Widget sender) {
        if (sender == editor) {
            notifyAllChangeListeners();
        }
    }

    public Widget getWidget() {
        return editor;
    }


}

然后把它填充到PropertyItem中去:
package com.google.gwt.sample.kitchensink.client.custom;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;

public class PropertyItem extends Composite {
    private String id;
    private HTML nameView;
    private BaseEditor valueView;
    private HorizontalPanel container = new HorizontalPanel();
/*    VerticalPanel left = new VerticalPanel();
    VerticalPanel right = new VerticalPanel();*/

    public PropertyItem(String id) {
        this(id, "label", EditorType.Text, "");
    }
   
    public PropertyItem(String id, String name, int editorType, String value) {
        this.id = id;
        setNameView(new HTML(name));
        setValueView(EditorFactory.create(editorType));
        setValue(value);
        adjustPosition();
        setWidget(container);
    }
   
    public void setNameView(HTML view) {   
        refresh(nameView, view, 0);
        nameView = view;
    }
   
    public void setValueView(BaseEditor view) {
        Widget widget = null;
        if (null != valueView) widget = valueView.getWidget();
        refresh(widget, view.getWidget(), 1);
        valueView = view;
    }
   
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
   
   
    public void setName(String name) {
        nameView.setHTML(name);
    }
   
    public void setValue(String value) {
        valueView.setValue(value);
    }
   
    public String getValue() {
        return valueView.getValue();
    }
   
    public String getName() {
        return nameView.getHTML();
    }
   
    public void addChangeListener(ChangeListener listener) {
        valueView.addChangeListener(listener);
    }

    public HTML getNameView() {
        return nameView;
    }

    public BaseEditor getValueView() {
        return valueView;
    }
   
    public void refresh(Widget oldView, Widget newView, int index) {
        int oldIndex = -1;
        if (oldView != null) oldIndex = container.getWidgetIndex(oldView);
        if (oldIndex != -1) container.remove(oldView);
        int setIndex = (oldIndex == -1) ? index : oldIndex;
        container.insert(newView, setIndex);
    }
   
    public void adjustPosition() {
        nameView.setStyleName("inspector-item-name");
        container.setCellWidth(nameView, "50%");
        container.setCellWidth(valueView.getWidget(), "50%");
        container.setCellVerticalAlignment(nameView, HasVerticalAlignment.ALIGN_MIDDLE);
        container.setCellVerticalAlignment(valueView.getWidget(), HasVerticalAlignment.ALIGN_MIDDLE);
        container.setCellHorizontalAlignment(nameView, HasHorizontalAlignment.ALIGN_LEFT);
        container.setCellHorizontalAlignment(valueView.getWidget(), HasHorizontalAlignment.ALIGN_LEFT);
    }
}



有了PropertyItem,把他们组合在一个垂直排列的panel内,就可以组成一个简单的PropertyEditor.

package com.google.gwt.sample.kitchensink.client.custom;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Inspector extends Composite {

   
    VerticalPanel container = new VerticalPanel();
    private List itemList = new ArrayList();
   
    public Inspector() {
        super();
       
        container.setStyleName("inspector");       
        setWidget(container);
       
    }
   
    public void addItemView(PropertyItem item) {
        container.add(item);
    }
   
    public void removeItemView(PropertyItem item) {
        container.remove(item);
    }
   
    public void addItem(PropertyItem item) {
        itemList.add(item);
        addItemView(item);
    }
   
    public void removeItem(PropertyItem item) {
        itemList.remove(item);
        removeItemView(item);
    }
  
    public void addItem(String id, String name, int editorType, String value) {
        addItem(new PropertyItem(id, name, editorType, value));
    }
   
    public PropertyItem getItem(String id) throws ItemNotFoundException {
        for (Iterator iter = itemList.iterator(); iter.hasNext();) {
            PropertyItem item = (PropertyItem)iter.next();
            if (item.getId().equalsIgnoreCase(id)) {
                return item;
            }
        }
        throw new ItemNotFoundException("item " + id + "not found");
    }
   
    public void removeItem(String id) throws ItemNotFoundException  {
        PropertyItem item = getItem(id);
        removeItem(item);
    }
   
    private void addChangeListenerInternal(String id, ChangeListener listener) throws ItemNotFoundException {
        getItem(id).addChangeListener(listener);
    }
   
    public boolean addChangeListener(String id, ChangeListener listener) {
        try {
            addChangeListenerInternal("t1", listener);
            return true;
        } catch (ItemNotFoundException e) {
            return false;
        }
    }
}



要在kitchensink项目中测试这个组件,可以仿造其中的Buttons类:

package com.google.gwt.sample.kitchensink.client;

import com.google.gwt.sample.kitchensink.client.custom.Editable;
import com.google.gwt.sample.kitchensink.client.custom.EditorType;
import com.google.gwt.sample.kitchensink.client.custom.Inspector;
import com.google.gwt.user.client.ui.*;

public class PropertyEditor extends Sink implements com.google.gwt.sample.kitchensink.client.custom.ChangeListener {

    public static SinkInfo init()  {
        return new SinkInfo("PropertyEditor",
            "Composite class build <code>PropertyEditor</code>") {
            public Sink createInstance() {
                return new PropertyEditor();
            }
        };
    }
   
   
    private void setInspector() {

          Inspector inspector = new Inspector();
          inspector.addItem("t1", "key", EditorType.Text, "dddd");
          inspector.addItem("t2", "cdasfas", EditorType.Text, "asdfsaf");

         
//        All composites must call setWidget() in their constructors.
          setWidget(inspector);
        
    }
   


    /**
     * Constructs an OptionalTextBox with the given caption on the check.
     *
     * @param caption the caption to be displayed with the check box
     */
    public PropertyEditor() {
      // Place the check above the text box using a vertical panel.

        setInspector();
       

      // Give the overall composite a style name.
      setStyleName("example-OptionalCheckBox");
    }


    public void onChange(Editable sender) {
        System.out.println(sender.getValue());
    }

   

}

当然,这很丑陋,可以利用css调整,不过我早告诉你,我对那些玩意不感兴趣。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值