作者:梁祺 ([email protected])
来自:http://www.benisoft.net/day6/index.html
昨天我们在介绍布局时,已经接触过对话框了,今天我们来看一下在实际应用中,对话框是怎么工作的。 对话框一般是提供给用户和应用程序交互的窗口,它分为模态对话框(Modal)和非模态对话框(Non-modal)。
- 模态对话框:用户必须完成对话框内的操作,关闭对话框以后才能继续操作对话框以外的应用程序。
- 非模态对话框:用户不必关闭对话框,也能继续操作对话框以外的应用程序。
一般情况,我们用到的都是模态对话框,所以我们主要介绍模态对话框,如果没有特别说明,对话框就指模态对话框。
在Itinerary的例子里,当用户创建一个出行计划时,我们使用对话框让用户输入新建出行计划的名称和简单描述, 点击OK来创建新的出行计划。
NewItineraryAction打开对话框New Itinerary(eclipse.tutorial.itinerary.dialogs.NewItineraryDialog), 当用户输入出行计划的名称,点击OK,从对话框对象dialog获取新创建的Itinerary对象,代码如下。
...
public void run(IAction action) {
NewItineraryDialog dialog = new NewItineraryDialog(window.getShell());
int result = dialog.open();
if (result == Window.OK) {
Itinerary itinerary = dialog.getItinerary();
...
}
}
NewItineraryDialog有三个成员变量。
- itinerary是新建的出行计划Itinerary对象,它是对话框的输出。
- textName和textDescription是两个UI控件成员变量,分别用以接受用户输入出行计划名称和简单描述。
private Itinerary itinerary;
private Text textDescription;
private Text textName;
对话框一个重要的部分就是控件的布局,一般都需要花费大量精力来设计对话框的布局,并加以实现,我们这个例子比较简单。 使用一个两列的GridLayout,第一行布置出行计划名称的控件,第二行布置描述的控件。
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
composite.setLayout(layout);
composite.setLayoutData( new GridData(SWT.FILL, SWT.FILL, true, true, 1,
1));
// Name
Label label = new Label(composite, SWT.NONE);
label.setText(\ "Name: \");
label.setLayoutData( new GridData(SWT.BEGINNING, SWT.BEGINNING, false,
false, 1, 1));
textName = new Text(composite, SWT.BORDER);
textName.setLayoutData( new GridData(SWT.FILL, SWT.BEGINNING, true,
false, 1, 1));
// Description
label = new Label(composite, SWT.NONE);
label.setText(\ "Description: \");
label.setLayoutData( new GridData(SWT.BEGINNING, SWT.BEGINNING, false,
false, 1, 1));
textDescription = new Text(composite, SWT.BORDER | SWT.MULTI);
textDescription.setLayoutData( new GridData(SWT.FILL, SWT.FILL, true,
true, 1, 1));
return composite;
}
对话框另一个部分是对用户输入进行验证,在很多应用里,这部分是比较繁琐的,关键是心里需要有个清晰的定义, 有文档描述就更好(这个好像只有产品级的应用里才会专门有人做这个设计)。这个例子里要求出行计划名称是必须输入的, 实现也很简单,如果用户没有输入出行计划名称,就把OK按钮变灰,无法创建出行计划。这样做不太严谨,好在例子程序 大家也能看明白,所以问题不大。比较好的做法是用TitleAreaDialog,用警告的方式告诉用户需要输入出行计划名称。
既然对话框一开始就没有出行计划名称,我们就需要在OK按钮创建完成后立刻将它变灰,这个需要重载createButtonsForButtonBar(), 先调用父类的createButtonsForButtonBar()来创建Cancel按钮和OK按钮,然后将OK按钮变灰。另外还需要为textName 添加事件处理器来获取文本框的修改事件,如果文本框内容为空,将OK按钮变灰,否则,恢复OK按钮。
super.createButtonsForButtonBar(parent);
getButton(OK).setEnabled( false);
}
void addListeners() {
textName.addModifyListener( new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
getButton(OK).setEnabled(! textName.getText().isEmpty());
}});
}
对话框最后一部分是从控件中获取数据,通过某种方式返回给调用者。在这个例子里, 当用户输入出行计划名称和描述,点击OK按钮后,Eclipse会调用okPressed()方法。在这个方法里,从textName和 textDescription获取名称和简单描述后,创建Itinerary对象,保存在itinerary成员变量上, 最后通过getItinerary()方法传递出去。这是一个常规的做法。
protected void okPressed() {
String name = textName.getText();
String description = textDescription.getText();
itinerary = new Itinerary(name);
itinerary.setDescription(description);
super.okPressed();
}
对话框我们就介绍到这里,其实很简单,就三个部分,控件布局,输入验证,以及返回数据给调用者。不过实现和测试 的工作量都比较大,估计工作量的时候要有充分的余量。