
選中站點點擊「連接」按鈕,自動填充主機、埠號、用戶名至主視窗,密碼欄清空並取得焦點。

// 站點管理器中的連接邏輯
if (command.equals("link")) {
frame.setLinkInfo(bean); // 傳遞 SiteInfoBean
dispose(); // 關閉對話框
}
public void setLinkInfo(SiteInfoBean bean) {
serverTextField.setText(bean.getServer());
portTextField.setText(String.valueOf(bean.getPort()));
userTextField.setText(bean.getUserName());
PassField.setText(""); // 密碼清空(安全性)
PassField.requestFocus(); // 密碼框取得焦點
}

@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("ok")) {
try {
String siteName = siteNameField.getText().trim();
String server = siteAddressField.getText().trim();
String userName = loginUserField.getText().trim();
String portStr = portField.getText().trim();
// 驗證必填欄位
if (siteName.isEmpty() || server.isEmpty()
|| userName.isEmpty() || portStr.isEmpty()) {
JOptionPane.showMessageDialog(this, "請填寫全部信息");
return;
}
int port = Integer.parseInt(portStr);
SiteInfoBean bean = new SiteInfoBean(siteName, server, port, userName);
// 編輯模式保留 ID
if (siteBean != null) bean.setId(siteBean.getId());
dialog.addSite(bean); // 父視窗新增站點
dialog.loadSiteList(); // 重新載入列表
dispose();
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(this, "請正確填寫端口號信息");
}
} else if (command.equals("cancel")) {
if (siteBean == null) clearInput(); else initInput();
}
}

邏輯同新增,差別在於開啟時預填現有站點資料(siteBean 不為 null)。
public void delSite(SiteInfoBean bean) {
siteInfo.remove(bean.getId()); // 從 Properties 移除
try (FileOutputStream out = new FileOutputStream(FILE)) {
siteInfo.store(out, "FTP站點數據"); // 持久化
loadSiteList(); // 重新載入列表
} catch (IOException e) { e.printStackTrace(); }
}
採用 java.util.Properties 儲存站點資料,鍵為站點 ID,值為序列化字串。
隊列面板 QueuePanel.refreshQueue() 中判斷:
private synchronized void refreshQueue() {
// 自動關機按鈕啟用 且 上傳/下載隊列皆為空
if (frame.getShutdownButton().isSelected()
&& localQueue.isEmpty() && ftpQueue.isEmpty()) {
try {
// Windows 關機命令:30秒倒數
Runtime.getRuntime().exec("shutdown -s -t 30");
} catch (IOException e) { e.printStackTrace(); }
}
// ... 更新隊列表格顯示
}
跨平台考量:僅支援 Windows。Linux/macOS 需 shutdown -h +1 或 systemctl poweroff,建議抽象平台介面。

最小化視窗時縮至系統托盤,右鍵選單提供「顯示主視窗」與「退出」。
private void initSystemTray() {
if (!SystemTray.isSupported()) return; // 平台不支援則跳過
systemTray = SystemTray.getSystemTray();
TrayIcon trayIcon = new TrayIcon(icon.getImage());
PopupMenu popupMenu = new PopupMenu("托盤選單");
// 顯示主視窗
MenuItem showItem = new MenuItem("顯示主視窗");
showItem.addActionListener(e -> {
FTPClientFrame.this.setExtendedState(JFrame.NORMAL);
FTPClientFrame.this.setVisible(true);
});
// 退出程式
MenuItem exitItem = new MenuItem("退出");
exitItem.addActionListener(e -> System.exit(0));
popupMenu.add(showItem);
popupMenu.addSeparator();
popupMenu.add(exitItem);
trayIcon.setPopupMenu(popupMenu);
try {
systemTray.add(trayIcon);
} catch (AWTException e) { e.printStackTrace(); }
}
| 模組 | 核心類別 | 關鍵技術點 |
|---|---|---|
| 站點管理 | SiteManagerDialog, SiteDialog, SiteInfoBean | Properties 持久化、Bean 資料傳遞、輸入驗證 |
| 自動關機 | QueuePanel | Runtime.exec 平台命令、隊列狀態監聽 |
| 系統托盤 | FTPClientFrame | SystemTray API、JFrame 狀態控制、AWT 事件處理 |
SystemControlService 介面,依平台注入實現本文完成了 FTP 客戶端的輔助功能模組:站點管理實現連線資訊的持久化與快速填充,自動關機提供批次傳輸後的便利性,系統托盤實現背景常駐運行。這些功能雖非核心傳輸邏輯,但大幅提升實用性與用戶體驗,是桌面應用專業度的重要體現。