SWT 支持几种输入离散值的方法。Scale 允许在(通常很小的)整数范围内挑选一个值。Slider 允许使用类似滚动条的方法在(可能很大的)整数范围内挑选一个值。Spinner 允许挑选(通过向前/撤退按钮)或键入一个(可能为小数的)数字。注意,Spinner 是 Eclipse V3.1 中的一个新特性。ProgressBar 类似于一个只输出的 Slider,因为可以用它来展示增量活动(进度)。
通常,这些控件允许您提供最小值、最大值和初始值。除了 ProgressBars 之外,这些控件还支持增量值和页面增量值,Sliders 还支持 thumb 宽度。图 4 展示了一个 GUI,它在控件组内包含一个 Slider、一个 Spinner 和一个 Scale,在这些控件的下方是一个 ProgressBar。紧贴在进度条上的是一个(居中的)Label,它展示了进度条的值。
图 4. 控件的例子
必须将所有这些控件定义为以下两种相互排斥的样式之一:
HORIZONTAL —— 水平地布置控件。
VERTICAL —— 垂直地布置控件。
Spinners 支持其他一些可选样式:
WRAP —— 从高值向低值换行排列。
READ_ONLY —— 不允许键入输入值。
ProgressBars 支持其他一些可选样式:
SMOOTH —— 更新不是在截然不同的步骤中进行的。
INDETERMINATE —— 没有预先确定步骤数的范围;进度条只是在时间上重复。
要创建这些控件,可以使用清单 6-9 中所示的代码。将通过 registerCallback 方法,使用 Java 反射将 SelectionListeners 添加到这些控件中。每当控件的值发生更改时,都会调用此侦听器。
清单 6. 用于创建 Slider 的方法
2 int min, int current, int max,
3 int inc, int pageinc, int thumb,
4 String callback) {
5 Slider s = new Slider(parent, style);
6 if (min >= 0) {
7 s.setMinimum(min);
8 }
9 if (max >= 0) {
10 s.setMaximum(max);
11 }
12 if (current >= 0) {
13 s.setSelection(current);
14 }
15 if (inc >= 1) {
16 s.setIncrement(inc);
17 }
18 if (pageinc >= 1) {
19 s.setPageIncrement(pageinc);
20 }
21 if (thumb >= 1) {
22 s.setThumb(thumb);
23 }
24 if (callback != null) {
25 registerCallback(s, this, callback);
26 }
27 return s;
28 }
29 protected Slider createVSlider(Composite parent,
30 int min, int current, int max,
31 int inc, int pageinc, int thumb,
32 String callback) {
33 return createSlider(parent, SWT.VERTICAL, min, current, max,
34 inc, pageinc, thumb, callback);
35 }
36 protected Slider createHSlider(Composite parent,
37 int min, int current, int max,
38 int inc, int pageinc, int thumb,
39 String callback) {
40 return createSlider(parent, SWT.HORIZONTAL, min, current, max,
41 inc, pageinc, thumb, callback);
42 }
43
清单 7. 用于创建 Spinner 的方法
2 int min, int current, int max,
3 int inc, int pageinc, String callback) {
4 Spinner s = new Spinner(parent, style);
5 if (min >= 0) {
6 s.setMinimum(min);
7 }
8 if (max >= 0) {
9 s.setMaximum(max);
10 }
11 if (current >= 0) {
12 s.setSelection(current);
13 }
14 if (inc >= 1) {
15 s.setIncrement(inc);
16 }
17 if (pageinc >= 1) {
18 s.setPageIncrement(pageinc);
19 }
20 if (callback != null) {
21 registerCallback(s, this, callback);
22 }
23 return s;
24 }
25
清单 8. 用于创建 Scale 的方法
2 int min, int current, int max,
3 int inc, int pageinc) {
4 Scale s = new Scale(parent, style);
5 if (min >= 0) {
6 s.setMinimum(min);
7 }
8 if (max >= 0) {
9 s.setMaximum(max);
10 }
11 if (current >= 0) {
12 s.setSelection(current);
13 }
14 if (inc >= 1) {
15 s.setIncrement(inc);
16 }
17 if (pageinc >= 1) {
18 s.setPageIncrement(pageinc);
19 }
20 return s;
21 }
22 protected Scale createVScale(Composite parent,
23 int min, int current, int max,
24 int inc, int pageinc) {
25 return createScale(parent, SWT.VERTICAL, min, current, max,
26 inc, pageinc);
27 }
28 protected Scale createHScale(Composite parent,
29 int min, int current, int max,
30 int inc, int pageinc) {
31 return createScale(parent, SWT.HORIZONTAL, min, current, max,
32 inc, pageinc);
33 }
34
清单 9. 用于创建 ProgressBar 的方法
2 int min, int current, int max) {
3 ProgressBar pb = new ProgressBar(parent, style);
4 if (min >= 0) {
5 pb.setMinimum(min);
6 }
7 if (max >= 0) {
8 pb.setMaximum(max);
9 }
10 if (current >= 0) {
11 pb.setSelection(current);
12 }
13 return pb;
14 }
15 protected ProgressBar createVProgressBar(Composite parent,
16 int min, int current, int max) {
17 return createProgressBar(parent, SWT.VERTICAL, min, current, max);
18 }
19 protected ProgressBar createHProgressBar(Composite parent,
20 int min, int current, int max) {
21 return createProgressBar(parent, SWT.HORIZONTAL, min, current, max);
22 }
23
您可以查询或设置这些控件的当前值。考虑一下清单 10 中定义的线程,该线程将更新 图 4 中的标签、进度条和滑块。此线程在选中“Automatic Update”按钮(即代码中的 modeButton)时启动。
清单 10. 用于更新控件的线程
2 protected int delay;
3 protected Display display;
4 public BarUpdater(Display display) {
5 this.display = display;
6 }
7 public void run() {
8 try {
9 while (true) {
10 try {
11 if (!display.isDisposed()) {
12 display.syncExec(new Runnable() {
13 public void run() {
14 if (!modeButton.isDisposed() &&
15 !scale.isDisposed()) {
16 delay = modeButton.getSelection()
17 ? scale.getSelection() : -1;
18 }
19 }
20 });
21 if (delay >= 0) {
22 Thread.sleep(delay);
23 if (!display.isDisposed()) {
24 display.syncExec(new Runnable() {
25 public void run() {
26 if (!bar.isDisposed()) {
27 int v = bar.getSelection() + 1;
28 if (v > bar.getMaximum()) {
29 v = bar.getMinimum();
30 }
31 bar.setSelection(v);
32 if (!slider.isDisposed()) {
33 slider.setSelection(v);
34 }
35 if (!valueLabel.isDisposed()) {
36 valueLabel.setText(
37 Integer.toString(v));
38 }
39 }
40 }
41 });
42 }
43 }
44 }
45 Thread.sleep(100);
46 }
47 catch (InterruptedException ie) {
48 }
49 }
50 }
51 catch (Exception e) {
52 e.printStackTrace();
53 }
54 }
55 }
56
注意,此代码小心地进行检查,看各种控件在使用之前是否已经就绪。在异步 GUI 操作中,这很关键。还会注意到,所有 GUI 访问都是在一个 syncExec(或其同类 asyncExec)方法中进行的。每当在与创建 GUI 所在的线程不同的线程上访问 GUI 时,都需要这样做。