本站首页 返回顶部 关于博主

改进下拉列表框

PDF版

  用Eclipse做Java开发的朋友应该知道SWT中下拉列表框Combo。
  在SWT自定义控件中,引入了CCombo,它也实现了Combo的功能。与Combo不同的是,它不是系统的native控件,而是通过Text、Button、List、Shell这几个控件组合而成的,不过用起来可能与Combo并没有什么不同。

问题提出

  在Eclipse BIRT中,有这样的功能:
  打开New Map Rule对话框,如下图所示,右边用记号标出来的区域,当用户点击倒三角符号时,下拉菜单会出现

  <Select Value…>和<Expression Builder…>这儿,下拉菜单只是起到Menu的作用。当选择不同的菜单时,就会触发不同的事件,而不是像普通的Combo一样,把当前选项作为值赋给Combo。此处,当选择<Selection Value…>时,就会弹出Select Value对话框,如下图所示:

  如果用户选中其中的某一个值,点“OK”,它的值就会返回到Combo中去。

  在实现这个功能的时候,我曾经试图给Combo加几个简单Listener来实现这样的功能。后来发现在不同的平台上,由于系统实现不一样,Linux或者Mac机上或多或少存在一些问题。于是,我给SWT发过bug:224837210908,希望SWT组能够让Combo在Linux和MacOS下能够像windows下一样正常工作。但他们迟迟没有修正,我不知道是不是平台不同,行为就不同。或许这种行为就是期望中的吧。

如何解决

  既然SWT不愿意修正,那就只能自己动手、丰衣足食了。
  要实现如上的功能,我有两种方法:
  1.封装Combo:把Combo的各种Listener进行封装,用一个新的class来管理Combo;
  2.改进CCombo:修改CCombo的代码,已达到改进的目的。

封装Combo

  先讲述如何封装Combo已达到所需的目标。
  由于Combo是平台相关的,不同的平台上,底层的实现是不一样的,因此我只能封装Combo,而不能改变Combo的内部实现,否则很难保证它能够真正的实现跨平台。
  在此,我通过创建一个新的class继承Combo,封装Combo的各种listener,部分代码如下:

public class ValueCombo extends Combo
{
  public static interface ISelection
   {
      public String[] doSelection( String input );
   }

    // add SelectionListener is forbidden, please use addSelectionListener(index
    // , selection) instead.
    public void addSelectionListener( SelectionListener listener )
    {
        // do nothing
    }

    // add KeyListener is forbidden
    public void addKeyListener( KeyListener listener )
    {
        // do nothing
    }

    public void addListener( int eventType, Listener listener )
    {
        if ( addListenerLock == true
          && ( eventType == SWT.Selection || eventType == SWT.KeyUp || eventType             == SWT.KeyDown ) )
        {
            return;
        }
        super.addListener( eventType, listener );
    }

    // index : [0, getItemCount - 1]
    public void addSelectionListener( int index, ISelection selection )
    {
        actionMap.put( index, selection );
    }

    // index : [0, getItemCount - 1]
    public void removeSelectionListener( int index )
    {
        actionMap.remove( index );
    }

   ………………
}

  ValueCombo封装了Combo,用户可以通过接口 public void addListener( int eventType, Listener listener )给ValueCombo添加事件,事件类型可以是除SWT.Selection、SWT.KeyUp和SWT.KeyDown之外Combo支持的所有事件。
  从实现来看,用户无法通过API添加SWT.Selection、SWT.KeyUp和SWT.KeyDown这三种类型的事件。是为什么禁止用户添加这三种类型的事件呢?因为在内部的逻辑处理过程中,我们必须用到这三种类型事件,为了防止用户添加事件而破坏内部的逻辑,这也是不得已而为之。
  但是,当用户选中ValueCombo中的一个item的时候,我们的确希望触发某些事件,那该怎么做呢?为此,我准备了ISelection.doSelection(String input)这个接口,用它来代替AddSelectionListener()。
  更多内容,可以参见代码和示例。

修改CCombo

  SWT中引入了CCombo,它不是系统native widget,而是通过几个native widget组合而成的,使用起来与native widget稍许有些差异。
  这儿,我写了一个CCombo,原封不动的把SWT的CCombo拷贝过来之后,稍微作了一点修改。
  加入了一个变量 boolean selEvent。如果selEvent为true,当用户选中CCombo中的某个item,item的值并不会马上填充到text框中。

代码示例

  这儿,我共享了所有的代码和示例。
  对源代码感兴趣的朋友点击<<此处>>下载。你也可以完全免费使用它,不过你必须遵循Eclipse Public License v1.0。如果你发现它有什么缺陷,或者有好的改进方法,欢迎与我联系。

(完)




请你留言