SWT中 Display 对象就是一个UI 线程。
若要访问UI 界面上的对象必须通过UI线程来访问,在非UI 线程内访问UI对象是不允许的。
我们看这个程序:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
public class ProgressBarComplex {
static boolean bCancel = false;
public static void main(String[] args){
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("ProgressBar");
shell.setLayout(new GridLayout(2,false));
final Button start = new Button(shell, SWT.NONE);
start.setText("开始");
Button cancel = new Button(shell, SWT.NONE);
cancel.setText("取消");
final ProgressBar progressBar = new ProgressBar(shell, SWT.HORIZONTAL);
GridData data = new GridData();
data.horizontalSpan = 2;
data.grabExcessHorizontalSpace = true;
progressBar.setLayoutData(data);
progressBar.setMaximum(100);
progressBar.setMinimum(0);
final int maximum = progressBar.getMaximum();
final int minimus = progressBar.getMinimum();
start.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
start.setEnabled(false);
Runnable runnable = new Runnable(){
public void run(){
for(int i=minimus;i<maximum;i++){
try{
Thread.sleep(100);
}catch(InterruptedException e){
}
//用 asyncExec 异步执行
shell.getDisplay().asyncExec(new Runnable(){
public void run(){
if(progressBar.isDisposed())
return;
if(bCancel){
progressBar.setSelection(0);
}
//只能在 UI 线程内调用,不能直接调用UI 元素的setSelection 函数
progressBar.setSelection(progressBar.getSelection()+1);
}
});
if(bCancel){
bCancel = false;
break;
}
}
}
};
new Thread(runnable).start();
}
});
cancel.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
if(!bCancel){
bCancel = true;
start.setEnabled(true);
}
}
});
shell.pack();
shell.open();
while(!shell.isDisposed()){
if(!display.readAndDispatch())
display.sleep();
}
}
}
函数 progressBar.setSelection() 是包含在一个Runnable 中,即在一个非UI 线程的线程中。由于progressBar 属于UI 对象,因此访问它的方法必须使用Dispaly 的线程调度方法,正如上面程序所示。
在Display 中进行线程调度的方法有3种:
1. asyncExec(Runnable): 异步执行线程,即这个调用的asyncExec 函数的线程可以和runnable 线程同步执行
2. syncExec(Runnable):等待runnable函数执行完毕才能继续。
3. timerExec(int milliseconds, Runnable runnable):等待一段时间后才开始新线程runnable。