简介
多数情况下,GUI界面编程不需要考虑线程问题,SWT已经帮助我们隐藏了底层的线程调用。但一些特殊应用,却不得不涉及SWT线程编程。
在实际项目开发中,一种常见的应用是:单击前台界面的执行后,在后台要做一些任务处理,任务执行情况要反映在界面上,而且还不能影响前台界面的其他操作这种应用的实现思路如下:
前台界面和后台程序分开2个类。
为后台程序另开一个线程,这样就可以让前台操作不受后台影响了。
前台界面提供一些可操作的组件的方法,后台处理程序调用这些方法,将执行情况的字符串写到前台界面组件中。
这种思路必须解决一个关键问题:界面本身有一个默认线程,后台程序又是另外一个线程。那么该如何在一个线程中访问另外一个线程呢?
(1) 为后台新开一个线程,这要用到JDK中线程的知识,代码如下:
new Thread()...{ // 新开一个线程,这是匿名内部类的写法
public void run()...{
//开始后台任务
}
}.start();//start表示立即开始线程
(2) 从后台处理线程中访问前台界面组件,关键在于使用display对象,因为display主要负责管理时间循环和控制UI线程和其他线程之间的通信。display的具体使用方法如下:
Display.getDefault().asyncExec(new Runnable()...{//又是一个匿名内部类写法
public void run()...{
//对前台界面的操作
}
});
在这里的display对象很关键,因此顺便给出得到display对象的2种方法:
Display.getDefault(),得到一个默认的display对象,应用程序一般只需要一个display对象。
Display.getCurrent(),得到当前运行线程所在的display对象,如果生成2个以上的display对象,则可用此方法。
一个SWT线程的实例:
本实例分2个类:一个前台界面类,一个后台处理类。实例功能说明如下:
单击“GO”按钮时,开始后台处理。
单击“STOP”按钮,立即中断后台处理。
后台处理的任务数根据前台界面文本框的值来决定。
进度条将实时反映后台处理的进度。
底部的文本框将以文字形式反映后台处理的进度情况。
实例具体代码如下:
1. 前台界面类
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
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.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class TaskGUI ...{
private Display display = Display.getDefault();
private Shell shell = new Shell();
private Task task = new Task(this);//Task是后台处理类,需要传入一个TaskGUI类型参数
//将界面组件设为类的实例变量
private Text taskCountText;//可输入任务数的文本框
private Button startButton;//开始
private Button stopButton;//结束
private ProgressBar progressBar;//显示的任务条
private Text consoleText;//显示当前后台进度的信息条
//主函数
public static void main(String[] args)...{
try...{
TaskGUI window = new TaskGUI();
window.open();
}catch(Exception e)...{
e.printStackTrace();
}
}
//前台页面的执行方法,显示出可操作的前台界面、
public void open() ...{
shell.setSize(300,300);
shell.setLayout(new GridLayout());
Group group = new Group(shell,SWT.NONE);
group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
group.setLayout(new GridLayout(4,false));
new Label(group,SWT.NONE).setText("taskCount:");
taskCountText = new Text(group,SWT.BORDER);
taskCountText.setText("10");
taskCountText.setLayoutData(new GridData(100,-1));
taskCountText.addVerifyListener(new VerifyListener()...{
public void verifyText(VerifyEvent e) ...{ //only input NO.
e.doit = "0123456789".indexOf(e.text)>=0;
}
});
startButton = new Button(group,SWT.PUSH);
startButton.setText("GO");
startButton.addSelectionListener(new SelectionAdapter() ...{//点击开始按钮
public void widgetSelected(SelectionEvent e) ...{
setButtonState(false);//点击后,2个Button发生变化
//得到任务数,多线程使用的变量要求类型为final
String str = taskCountText.getText();
final int taskCount = new Integer(str).intValue();
//设置进度条的格数
progressBar.setMaximum(taskCount-1);
consoleText.insert("back Thread run start... ... ");
//为后台新开一个线程,运行,当run方法结束(即后台的start()结束),线程自动销毁
new Thread()...{
public void run()...{
task.start(taskCount);
}
}.start();
consoleText.insert("back Thread run end... ... ");
}
});
stopButton = new Button(group,SWT.PUSH);
stopButton.setText("STOP");
stopButton.setEnabled(false);
stopButton.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
task.stop();//后台执行stop方法,实际是要后台任务停止
}
});
progressBar = new ProgressBar(shell,SWT.NONE);
progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
//下面2个是设置,文本框的显示格式,第2行的如果不加则会看不到全部信息了
consoleText = new Text(shell,SWT.MULTI|SWT.BORDER|SWT.V_SCROLL);
consoleText.setLayoutData(new GridData(GridData.FILL_BOTH));
shell.layout();
shell.open();
while(!shell.isDisposed())...{
if(!display.readAndDispatch())...{
display.sleep();
}
}
}
public void setButtonState(boolean bFlag)...{//设置页面的2个按钮状态
startButton.setEnabled(bFlag);
stopButton.setEnabled(!bFlag);
}
//为后台取得页面组件写的几个GET方法
public Shell getShell()...{
return shell;
}
public Text getConsoleText()...{
return consoleText;
}
public ProgressBar getProgressBar()...{
return progressBar;
}
}
2. 后台任务类
import org.eclipse.swt.widgets.Display;
public class Task ...{
private TaskGUI gui;//通过构造器得到前台界面对象
private boolean stopFlag;//是否停止的标志
//构造器 取得前台界面对象
public Task(TaskGUI taskGUI)...{
this.gui = taskGUI;
}
public void stop()...{
stopFlag = true;
}
//就是前台run方法的执行内容,这个方法结束,则前台new的那个线程销毁
public void start(int taskCount)...{
stopFlag = false;//将执行状态初始化执行
insertConsoleText("backGO start ... ... ");
for(int i=0;i<taskCount;i++)...{
if(stopFlag)...{//点击stop按钮则这个属性为true,跳出循环
break;
}
try...{//每隔1秒一次循环
Thread.sleep(1000);
}catch(InterruptedException e)...{
e.printStackTrace();
}
//页面上的信息累加
insertConsoleText("task"+(i+1)+"the end ");
//移动进度条的进度
moveProgressBar(i);
}
insertConsoleText("the thread end of the task!! ");
setTaskGUIButtonState(true);
}
//修改页面按钮的状态
private void setTaskGUIButtonState(final boolean bFlag)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.setButtonState(bFlag);
}
});
}
private void moveProgressBar(final int progress)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.getProgressBar().setSelection(progress);
}
});
}
private void insertConsoleText(final String str)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.getConsoleText().insert(str);
}
});
}
}
程序说明:
从上面代码的执行结果可以看到,前台new 了一个新的 thread 后,后面的那句文本依然可以输出,可以明确的说明,new了一个线程后,前台,后台线程是互不干扰的独自运行。当start方法结束时,后台的线程就自动销毁。
原文:http://www.cnblogs.com/mengtao-liu/p/4305021.html