本系列記錄一個基於 Java Swing 的記事本完整實現。第 3 篇聚焦核心交互邏輯:菜單/右鍵事件分發、查找替換模態對話框、字體選擇對話框,展示 Swing 事件模型與自定義組件開發實戰。
實現 ActionListener 接口,actionPerformed 方法作為總控制器,根據 e.getSource() 分發至具體業務方法:
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == jMenuFileCut || src == jMenuMouseCut) { fileCut(e); }
else if (src == jMenuFileCopy || src == jMenuMouseCopy) { fileCopy(e); }
else if (src == jMenuFilePaste || src == jMenuMousePaste) { filePaste(e); }
else if (src == jMenuFileDel || src == jMenuMouseDel) { fileDel(e); }
else if (src == jMenuFileFindNext) { fileFindNext(e); }
else if (src == jMenuFileSelect) { allSelect(e); }
else if (src == jMenuFileTime) { fileTime(e); }
else if (src == jMenuCheckBox) { if (check) fileLine(e); }
else if (src == jMenuFileFont) { new Bfont(jTextArea1); } // 打開字體對話框
else if (src == jcolor) { fcolor(e); } // 顏色選擇
else if (src == jMenuHelpAbout) { helpAboutDialog(e); }
}
設計亮點:菜單項與右鍵項共用同一處理方法,消除重複代碼;check 狀態變量控制查找大小寫敏感切換。
find():根據方向在 jTextArea1 全文中定位,高亮選中 (select(start, end))replace():針對當前選中區域替換文本 (replaceRange(text, start, end))Button1Listener、Button2Listener、Button3Listener 分離按鈕邏輯public void find() {
String text1 = jTextField1.getText();
if (check) text1 = text1.toLowerCase(); // 大小寫不敏感
int i = jTextArea1.getSelectionStart();
int t = jTextArea1.getSelectionEnd();
String findStr = check ? jTextArea1.getText().toLowerCase() : jTextArea1.getText();
if (teams[0].isSelected()) { // 向上搜索
String prefix = findStr.substring(0, i);
int index = prefix.lastIndexOf(text1);
if (index != -1) jTextArea1.select(index, index + text1.length());
else JOptionPane.showMessageDialog(this, "找不到" + text1);
} else { // 向下搜索
int index = findStr.indexOf(text1, t);
if (index != -1) {
t = index + text1.length();
jTextArea1.select(index, index + text1.length());
} else JOptionPane.showMessageDialog(this, "找不到" + text1);
}
repaint();
}
JList:字體族 (data1)、字型 (data2: 常規/斜體/粗體/粗斜體)、字號 (data3: 10~20)jTextField1)、字符集下拉框 (jComboBox1)ziti/zixing/daxiaovoid sfont() {
jTextArea1.setFont(new Font(ziti, zixing, daxiao));
}
// zixing 映射:Font.PLAIN / ITALIC / BOLD / (BOLD|ITALIC)
為每個頂級菜單項創建專用適配器類,將 actionPerformed 轉發至具體業務方法,避免主類膨脹:
class File_new_actionAdapter implements ActionListener {
public void actionPerformed(ActionEvent e) { File_new_actionPerformed(e); }
}
// 類似:File_open_actionAdapter, File_save_actionAdapter...
| 現狀 | 問題 | 改進方向 |
|---|---|---|
| 巨型類包含所有邏輯 | 單一職責違背,難測試、難維護 | 拆分:NotepadController、FindReplaceDialog、FontChooserDialog、TextAreaModel |
| 硬編碼字體列表 | 跨平台字體不可用、無法擴展 | GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames() 動態獲取 |
| 查找邏輯區分大小寫轉換全文 | 大文件性能差、修改原文案 | 使用 Highlighter + DefaultHighlighter.DefaultHighlightPainter 高亮,不修改文本 |
| 無撤銷/重做支援 | 核心編輯器缺失 | 引入 UndoManager + DocumentListener 實現 |
| 單線程處理大文件操作 | UI 凍結 | SwingWorker 異步加載/保存 |
public static void main(String[] args) {
// 建議包裝在 SwingUtilities.invokeLater 中確保 EDT 安全
SwingUtilities.invokeLater(() -> new Notepad());
}
雖然代碼風格屬於 Swing 早期典型寫法,但完整展示了「事件分發→業務方法→模態對話框→組件交互」的經典桌面應用開發範式,對理解事件驅動架構極具教學價值。