長期以來,AWT/Swing 的異質外觀、高資源消耗、執行效能差,讓 Java 桌面應用難獲用戶青睞。Standard Widget Toolkit (SWT) 由 Eclipse 專案組開發,最大化利用作業系統原生圖形元件(透過 JNI 呼叫),僅在 OS 缺乏對應元件時自行模擬。結果:標準原生外觀、接近 C/C++ 效能、跨平台無縫移植。SWT API 穩定度高,版本升級通常僅需替換 swt.jar 與原生庫即可。
+ swt (專案根目錄)
+ bin (編譯輸出)
+ src (原始碼)
+ AddressBookUI.java
+ swt-awt-win32-3062.dll
+ swt-win32-3062.dll
+ javaw.exe.manifest
(以上 DLL/Manifest 來自 eclipse/plugins/org.eclipse.swt.win32_3.0.1/os/win32/x86)
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
public class AddressBookUI {
private Shell shell;
private Text miscText, addrText, emailText, phoneText, lnameText, fnameText;
private Button cancelButton, saveButton, nextButton, prevButton, editButton, deleteButton, newButton;
public static void main(String[] args) {
new AddressBookUI().open();
}
public void open() {
Display display = new Display();
shell = new Shell(display);
shell.setSize(610, 477);
shell.setText("Address Book");
// 建立 7 個功能按鈕:New, Delete, Edit, Previous, Next, Save, Cancel
createButton("New", 10, e -> { clearText(); setEditable(true); enableEditBtns(false); enableSaveBtns(true); });
createButton("Delete", 85, e -> { clearText(); System.out.println("Delete"); });
createButton("Edit", 160, e -> { setEditable(true); enableEditBtns(false); enableSaveBtns(true); });
createButton("Previous", 265, e -> System.out.println("Previous"));
createButton("Next", 340, e -> System.out.println("Next"));
saveButton = createButton("Save", 445, e -> { setEditable(false); enableEditBtns(true); enableSaveBtns(false); });
saveButton.setEnabled(false);
cancelButton = createButton("Cancel", 520, e -> { setEditable(false); enableEditBtns(true); enableSaveBtns(false); });
cancelButton.setEnabled(false);
// 建立詳細資料群組
Group group = new Group(shell, SWT.NONE);
group.setText("Details");
group.setBounds(10, 10, 585, 355);
String[] labels = {"First Name:", "Last Name:", "Phone:", "Email:", "Address:", "Miscellaneous Information:"};
int[] yPos = {20, 60, 100, 140, 180, 255};
Text[] fields = {fnameText, lnameText, phoneText, emailText, addrText, miscText};
int[] styles = {SWT.BORDER | SWT.READ_ONLY, SWT.BORDER | SWT.READ_ONLY,
SWT.BORDER | SWT.READ_ONLY, SWT.BORDER | SWT.READ_ONLY,
SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL,
SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL};
for (int i = 0; i < labels.length; i++) {
new Label(group, SWT.NONE).setBounds(10, yPos[i], 135, 25).setText(labels[i]);
fields[i] = new Text(group, styles[i]);
fields[i].setBounds(150, yPos[i] - 5, 420, i >= 4 ? 60 : 25);
}
// 實際需將 fields 陣列元素賦值給對應欄位變數
setupMenu();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
private Button createButton(String text, int x, SelectionListener listener) {
Button btn = new Button(shell, SWT.NONE);
btn.setBounds(x, 380, 75, 35);
btn.setText(text);
btn.addSelectionListener(listener);
return btn;
}
private void setupMenu() {
Menu menuBar = new Menu(shell, SWT.BAR);
shell.setMenuBar(menuBar);
MenuItem file = new MenuItem(menuBar, SWT.CASCADE);
file.setText("File");
Menu fileMenu = new Menu(file);
file.setMenu(fileMenu);
createMenuItem(fileMenu, "Previous", SWT.NONE, e -> System.out.println("Previous"));
createMenuItem(fileMenu, "Next", SWT.PUSH, e -> System.out.println("Next"));
new MenuItem(fileMenu, SWT.SEPARATOR);
createMenuItem(fileMenu, "Quit", SWT.PUSH, e -> shell.dispose());
}
private void createMenuItem(Menu parent, String text, int style, Listener listener) {
MenuItem item = new MenuItem(parent, style);
item.setText(text);
item.addListener(SWT.Selection, listener);
}
private void clearText() { /* 清空所有 Text 欄位 */ }
private void setEditable(boolean b) { /* 設定所有 Text editable 狀態 */ }
private void enableEditBtns(boolean b) { newButton.setEnabled(b); deleteButton.setEnabled(b); editButton.setEnabled(b); }
private void enableSaveBtns(boolean b) { saveButton.setEnabled(b); cancelButton.setEnabled(b); }
}
readAndDispatch()/sleep() 是 SWT 應用的心跳,處理原生事件佇列setBounds(x, y, w, h) 絕對定位,簡單直接;複雜介面可改用 GridLayout、FormLayoutdispose(),避免 OS 句柄洩漏swt-*.dll/.so 並設定 java.library.path專案設定完成後,直接 Run As Java Application 即可啟動通訊錄視窗。按鈕點擊、選單操作、欄位編輯狀態切換皆在 Console 輸出對應日誌,驗證事件綁定正確性。