在開發基於Java的FTP客戶端時,建立直觀且功能完善的任務隊列界面至關重要。本文詳細介紹如何使用Swing構建上傳/下載隊列窗口,涵蓋界面佈局、任務調度、進度顯示及交互控制等核心功能。
隊列面板(QueuePanel)繼承自JPanel,採用BorderLayout佈局,中央區域放置任務表格(JTable),右側工具欄(JToolBar)提供上移、下移、暫停/繼續、刪除、清空等操作按鈕。表格採用DefaultTableModel,列定義為:「任務名稱、方向、主機、執行狀態」。
隊列維護兩個LinkedList<Object[]>:
localQueue:本地上傳隊列,元素為{File, FtpFile}對ftpQueue:遠程下載隊列,元素為{FtpFile, File}對一個Timer每秒檢查隊列總長度是否變化,若有變動則調用refreshQueue()重繪表格。刷新邏輯會遍歷兩個隊列,將任務轉為表格行:上傳任務顯示本地文件絕對路徑、方向「上傳」、目標主機、狀態(首項「正在上傳」其餘「等待上傳」);下載任務顯示遠程路徑、方向「下載」、主機、狀態同理。
JToggleButton切換stop標誌,上傳/下載線程在copyFile()/downFile()中輪詢此標誌,true時睡眠等待。
根據選中行的方向(上傳/下載)定位對應隊列,交換隊列中相鄰元素,隨後刷新表格並保持選中狀態。
刪除時依據第一列值類型(File或String)判斷隊列,移除匹配項;清空直接調用兩隊列的clear()。
UploadPanel與DownloadPanel結構相似,均包含不可選行的JTable,狀態列使用自定義QueueTableCellRanderer渲染進度條(封裝於ProgressArg)。addRow()通過SwingUtilities.invokeLater確保在EDT線程安全插入行。
package com.oyp.ftp.panel.queue;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import javax.swing.table.DefaultTableModel;
public class QueuePanel extends JPanel implements ActionListener {
private JTable queueTable = new JTable();
private final FTPClientFrame frame;
private final LinkedList<Object[]> localQueue, ftpQueue;
private final Timer queueTimer;
private boolean stop = false;
public QueuePanel(FTPClientFrame frame) {
this.frame = frame;
localQueue = (LinkedList<Object[]>) frame.getLocalPanel().getQueue();
ftpQueue = (LinkedList<Object[]>) frame.getFtpPanel().getQueue();
initComponent();
queueTimer = new Timer(1000, e -> {
if (localQueue.size() + ftpQueue.size() != queueTable.getRowCount())
refreshQueue();
});
}
private void initComponent() {
setLayout(new BorderLayout());
String[] columns = {"任務名稱", "方向", "主機", "執行狀態"};
queueTable.setModel(new DefaultTableModel(new Object[][]{}, columns));
queueTable.getTableHeader().setReorderingAllowed(false);
add(new JScrollPane(queueTable), BorderLayout.CENTER);
JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
toolBar.setFloatable(false);
String[] cmds = {"up", "down", "stop&start", "del", "clear"};
String[] labels = {"上移", "下移", "暫停", "刪除", "清空"};
for (int i = 0; i < cmds.length; i++) {
AbstractButton btn = (i == 2) ? new JToggleButton(labels[i]) : new JButton(labels[i]);
btn.setActionCommand(cmds[i]);
btn.addActionListener(this);
toolBar.add(btn);
if (i == 2) stopButton = (JToggleButton) btn;
}
add(toolBar, BorderLayout.EAST);
}
public void startQueue() { queueTimer.start(); }
@Override public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if ("stop&start".equals(cmd)) {
stop = stopButton.isSelected();
stopButton.setText(stop ? "繼續" : "暫停");
} else if ("up".equals(cmd) || "down".equals(cmd)) {
upDownAction(cmd);
} else if ("del".equals(cmd)) { deleteSelected(); }
else if ("clear".equals(cmd)) { localQueue.clear(); ftpQueue.clear(); refreshQueue(); }
}
private synchronized void refreshQueue() {
// 自動關機邏輯略
DefaultTableModel model = new DefaultTableModel(new String[]{"任務名稱","方向","主機","執行狀態"}, 0);
// 填充上傳任務
for (int i = 0; i < localQueue.size(); i++) {
File f = (File) localQueue.get(i)[0];
model.addRow(new Object[]{f.getAbsolutePath(), "上傳", frame.getFtpClient().getServer(),
i == 0 ? "正在上傳" : "等待上傳"});
}
// 填充下載任務
for (int i = 0; i < ftpQueue.size(); i++) {
FtpFile ff = (FtpFile) ftpQueue.get(i)[0];
model.addRow(new Object[]{ff.getAbsolutePath(), "下載", frame.getFtpClient().getServer(),
i == 0 ? "正在下載" : "等待下載"});
}
queueTable.setModel(model);
}
// upDownAction、deleteSelected、isStop 等輔助方法略
}



上傳/下載任務添加與完成狀態截圖:


本文完整呈現了FTP客戶端隊列模塊的設計思路與核心實現,為構建健壯的文件傳輸工具提供了參考範例。