| 网站首页 | 文章中心 | 电子书下载 | 矢量图库 | 视频教程 | 素材下载 | 程序代码下载 | JS代码 | 论坛 | 
常用软件类:
|杀毒安全 |联络聊天 |网络软件 |多媒体类 |系统工具 |图形图像 |系统工具 |应用软件 |行业软件
开发设计类:
|动画制作 |图像处理 |3D设计 |操作系统 |站长学院 |网络相关 |WEB设计 |数据库类 |程序开发
Java SWT实现MSN风格的下拉框
 



  还需要指出,通过添加绘制监听器来实现个性化的外观,并在调用影响外观的操作(比如setEnable)时调用redraw方法强制组件重绘,这是自定义组件常用的实现手段。你会看到接下来的很多方法会经常调用redraw通知组件重绘。

  除了setEnabled方法,还有一些方法需要补充,一并列出:

public void setEditable(boolean editable) {
inputText.setEditable(editable);
}

public String getText() {
return inputText.getText();
}

public void setText(String text) {
inputText.setText(text);
}

public void setTextLimit(int limit) {
inputText.setTextLimit(limit);
}

  这些方法简单易懂,不作解释,以上列举的只是最基本的方法,如果觉得功能不够还可以定义其他方法,例如可以对用户的输入作验证。

  接下来回到构造函数中来,QQ、MSN等一些软件的登录除了点击登录按钮执行还可以在用户名、口令输入框上单击回车来实现,为了实现这一功能,需要为基本文本组件添加一个选择监听器。

inputText.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
commit();
}
});

  这样,当用户在文本组件上单击回车,会执行commit方法。下面是commit方法的定义:

protected void commit() {};

  它不作任何事情,因为组件不知道实际会应用在何种场合,即回车操作具体作什么,这应该通过继承该组件重写commit方法实现具体功能。

  然后为组件添加鼠标监听器,实现用户单击下拉按钮时菜单的弹出。完整代码如下:

addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
if (e.x > getBounds().width - COMBO_ICON.getBounds().width - 15
&& e.x < getBounds().width && e.y > 0
&& e.y < getBounds().height) {
selectorMenu.setLocation(getScreemLocation().x + 3,
getScreemLocation().y + getSize().y + 23);
selectorMenu.setVisible(true);
}
}
});

  if条件句子是判断鼠标指针的落点是否位于下拉三角的区域内,计算方法读者可以自己思考,之后设置弹出菜单出现的位置,根据前面定义的getScreemLocation方法可方便得出,需要提出的是计算x坐标的“+3”和y坐标的“+23”,为什么要再加上这个整数呢?是因为Windows窗口的标题栏高20像素,而getScreemLocation是无法自动计算出的,有些窗口可通过设置将标题栏去掉(SWT的Shell通过指定SWT.NO_TRIM样式实现)“+3是使菜单弹出的位置不至于遮挡组件边框线,因此偏移3像素为最佳位置”。调用setVisible显示菜单,不过前提条件是必须添加了菜单项。构造函数最后是一步是设置组件为可用,虽然任何SWT/Swing组件在构造时默认都是可用的,但是正如前面所述,重写setEnabled并不止设置是否被禁用,重要的是组件在两态下的外观,所以在构造函数最后添加setEnabled(true);

  以上讲述过多的是如何装饰组件的外观,接下来的重点将介绍如何用该组件缓存数据,使用MSN时候会发现,单击登录用户名的下拉按钮时候,会弹出所有在本机登录过的用户名列表(如果保存的话),下面讲述如何实现这一功能。

  我们的数据均保存在Vector这个集合中,由于实际应用变化万千,组件不可能知道实际保存何种类型的数据,因此Vector的元素类型统一设置为Object,这也实在是一个不错的设计,因为它不强制使用者去实现某某接口,或基类,假如设计成Vector中的元素必须是实现某一特定接口IElement,

private Vector dataSet = new Vector();

  这样的话,使用者就必须将其POJO作更改,以适应于此组件,而Object作为所有类的基类,因此可容纳任何类型的数据。接下来的一步很重要,是将数据与菜单关联起来。定义如下方法public void loadMenuItems(Object[] objects),顾名思义是一次性读取一组元素,完整的代码如下:

public void loadMenuItems(Object[] objects) {
dataSet.clear();
MenuItem[] items = selectorMenu.getItems();
for (MenuItem item : items) {
item.removeSelectionListener(this);
item.dispose();
}
for (int i = 0; i < objects.length; i++) {
dataSet.add(objects[i]);
MenuItem item = new MenuItem(selectorMenu, SWT.PUSH);
item.setText(objects[i].toString());
item.setData(objects[i]);
item.addSelectionListener(this);
}
}

  因为是load所有数据,所以第一步是将已有的数据清空,包括Vector中的数据和菜单中的菜单项。然后是对传入的Object数组作遍历,对于每一项,将之添加进集合然后创建一个菜单项,下一步item.setText(objects[i].toString()); 是设置菜单项的文字,toString()方法是Object的固有方法,但是实际应用时必须重写该方法的实现。接下来是item.setData(objects[i]); 为菜单项设置数据,这一步非常重要,SWT的每一个组件都具有public void setData (Object data)和public Object getData ()方法。还有Hash结构的public void setData (String key, Object value)和public Object getData (String key)。稍后会看到通过item.getData(); 取出创建时存入的数据。最后一行是为菜单项添加事件监听器,并使组件本身作为监听器,使组件本身实现SelectionListener接口,然后添加下面两个方法:

public final void widgetDefaultSelected(SelectionEvent e)

public final void widgetSelected(SelectionEvent e)

  其中widgetDefaultSelected在单击回车时触发,对文本框这样的组件适用,widgetSelected是鼠标单击时触发适用于按钮、菜单项。因此我们只处理widgetSelected。

public final void widgetSelected(SelectionEvent e) {
MenuItem item = (MenuItem) e.getSource();
selectedItem = item.getData();
String text = item.getData().toString();
inputText.setText(text);
inputText.setSelection(0, text.length());
selected(item.getData());
}

  首先取得事件源即单击的菜单项,然后更新selectedItem引用指向这个菜单项保存的数据(先前通过setData方法添加的),接下来的代码不作解释,很容易理解。值得注意的是最后一行selected(item.getData()); 作用是当用户选中菜单某一项时,根据当前选择的那个数据自动执行相应的操作,selected方法定义如下:

protected void selected(Object object) {};

  与commit方法一样,是需要根据实际情况自定义处理逻辑的。

  最后添加如下2个方法:

public void select(int index) {
MenuItem[] items = selectorMenu.getItems();
if (index < 0 || index >= items.length) {
throw new ArrayIndexOutOfBoundsException(
"the index value must between " + 0 + "and "
+ (items.length - 1));
}
selectedItem = items[index].getData();
inputText.setText(items[index].getText());
}

  select用来设置当前选择第几个项,getSelectedItem返回当前用户选择的数据。

  到此为止,ComboSelector已经完成,可以作为API使用了,下面我们编写一个程序测试该组件。

  首先编写一个POJO,如下:

package swt.custom;

public class Person {
private String userName;

private String password;

public Person(String userName, String password) {
this.userName = userName;
this.password = password;
}

public String getPassword() {
return password;
}

public String getUserName() {
return userName;
}

@Override
public String toString() {
return userName;
}
}

  简单至极的一个类,注意它的toString方法,返回用户名属性作为显示。

  接下来通过一个demo看看实际运行效果。

  用swt-designer工具创建一个Shell,在createContents方法体内添加如下代码:

final ComboSelector selector = new ComboSelector(this) {
@Override
protected void commit() {
System.out.println("current data is "
+ ((Person) getSelectedItem()).getUserName());
}
@Override
protected void selected(Object object) {
System.out.println(((Person) object).getPassword());
}
};
selector.setBounds(114, 78, 200, 20);
Person[] persons = new Person[] {
new Person("play_station3@sina.com", "111111"),
new Person("rehte@hotmail.com", "222222"),
new Person("yitong.liu@bea.com", "password"),
new Person("使用其他Windows Live ID 登录", "no") };
selector.loadMenuItems(persons);
selector.select(1);

上一页  [1] [2] 


  • 上一篇文章:

  • 下一篇文章: 没有了
  • 相关文章