SWT中處理多線程
在Eclipse中,SWT是最重要的基石之一,負責了跨平臺的本地界面顯示,使Java也能夠編寫與系統相同的界面元素。在SWT中處理多線程也是其重要技術的表現。
SWT有兩個使用方法,分別是asyncExec和syncExec,前者是 異步執行與界面有關的操作,後者反之。爲什麼要這麼做?由於SWT單獨有一個線程(主線程)處理界面顯示,數據顯示等,如果要在其他線程中操作界面元素, 就必須使用上述兩個方法執行,即將另外線程的操作交給主線程處理。
而SWT的多線程遠沒有這麼簡單。一般情況下,在SWT中運行線程時,其主線程不能阻塞,也能響應用戶請求,比如鼠標和菜單等。在這種情況下,需要新建Thread來處理邏輯,在這個Thread中,必須使用上面的兩個方法處理界面數據。
以下是一個簡單的例子,啓動10個線程,在5秒的時間內,刷新列表中各行的字符串,在這個過程中,主界面依然能夠響應鼠標請求。代碼有點“圓環套圓環”的感覺。
import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; 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.List; import org.eclipse.swt.widgets.Shell;
/** * @author tenyears.cn */ public class SWTThread { private int size = 10; // 10 threads private long runTime = 5000; // 5 seconds private List list; private Shell shell; public void startThread() { for (int index = 0; index < size; index++) { final int listIndex = index; final Runnable refresh = new Runnable() { public void run() { final Display disp = shell.getDisplay(); final Runnable runOne = new Runnable() { public void run() { final long start = System.currentTimeMillis(); while ((System.currentTimeMillis() - start) < runTime) { disp.syncExec(new Runnable() { public void run() { if (list.isDisposed()) return; String string = "No." + listIndex; string += " " + (System.currentTimeMillis() - start); list.setItem(listIndex, string); } }); try { Thread.sleep(100); } catch (InterruptedException e) { } }; } }; Thread thread = new Thread(runOne); thread.start(); } }; BusyIndicator.showWhile(shell.getDisplay(), refresh);//這一句很關鍵 } }
public Shell open(final Display display) { shell = new Shell(display, SWT.DIALOG_TRIM | SWT.MIN); shell.setText("SWT Thread Test"); shell.setLayout(new GridLayout(1, true)); list = new List(shell, SWT.BORDER); list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); for (int index = 0; index < size; index++) list.add("String " + (index + 1)); Button startBtn = new Button(shell, SWT.PUSH); startBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); startBtn.setText("Start"); SelectionAdapter selection = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { startThread(); } }; startBtn.addSelectionListener(selection); shell.setSize(400, 300); shell.open(); return shell; }
public static void main(String[] args) { Display display = new Display(); SWTThread application = new SWTThread(); Shell shell = application.open(display); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }
|
說明:
下面分析startThread()
這個方法可以用於當這個方法的執行需要很長時間,而在其執行期間又不會影響其他方法的執行。本方法中的最後一句:
BusyIndicator.showWhile(shell.getDisplay(), refresh);
是關鍵,如果沒有這一句則,執行此方法時,其他方法不能運行。
這個方法的必須包含兩個Runnable的是實現:其中外層用於
BusyIndicator.showWhile()方法中作爲參數
長時間的運行代碼應該放在裏面的一個runnable實現的run()方法中,例如:
final Runnable runOne = new Runnable() {
public void run() {
final long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 1000*10) {
cnt++;
}
};
};
startThread方法可以簡化爲:(這個方法更清晰)
public void startThread() {
final Runnable refresh = new Runnable() {
public void run() {
final Runnable runOne = new Runnable() {
public void run() {
final long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 1000*10) {
cnt++;
}
};
};
Thread thread = new Thread(runOne);
thread.start();
}
};
BusyIndicator.showWhile(shell.getDisplay(), refresh);
}