【转】SWT Designer 下 SWT的线程
多数情况下,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方法结束时,后台的线程就自动销毁。
import?org.eclipse.swt.SWT;