首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 記事本程式 (一):Swing GUI 架構與選單系統完整建構

     編輯:Java 程式設計入門

專案簡介

課程設計作品:模擬 Windows 記事本功能的 Swing 桌面應用。包含檔案 (新建/開啟/儲存/另存為/結束)、編輯 (撤銷/剪貼簿/搜尋取代/全選/時間戳)、格式 (自動換行/字體/顏色)、說明 (關於) 完整選單系統、右鍵彈出選單、狀態列、捲軸文本區。本篇著重 GUI 建構與事件適配器註冊;核心邏輯見下篇。

主類別 Jsb 結構


package jeason;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.io.*;
import java.util.*;
import java.text.*;

public class Jsb {
    // 狀態欄位
    private boolean dirty = false;   // 內容是否已修改
    private String filename = "";    // 當前檔案路徑
    private String strtext = "";     // 暫存文本 (搜尋用)

    // UI 元件
    private JFrame frame = new JFrame("我的記事本");
    private JPopupMenu pop = new JPopupMenu("彈出選單");
    private JTextArea text = new JTextArea();
    private JLabel statusBar = new JLabel("就緒");
    private JMenuBar menuBar = new JMenuBar();
    private JFileChooser fileChooser = new JFileChooser();
    private JColorChooser colorChooser = new JColorChooser();

    // 選單物件
    private JMenu mFile, mEdit, mFormat, mHelp;
    private JMenuItem miNew, miOpen, miSave, miSaveAs, miExit;
    private JMenuItem miUndo, miCut, miCopy, miPaste, miDelete, miFind, miReplace, miSelectAll, miTimeDate;
    private JMenuItem miWordWrap, miFont, miColor;
    private JMenuItem miAbout;

    public Jsb() { initUI(); }

    private void initUI() {
        // 視窗基本設定
        frame.setSize(600, 500);
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // 自行處理關閉
        frame.addWindowListener(new WindowAdapter() {
            @Override public void windowClosing(WindowEvent e) { close(); }
        });

        // 主面板:BorderLayout 中央文本區+捲軸,南部狀態列
        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(new JScrollPane(text), BorderLayout.CENTER);
        mainPanel.add(statusBar, BorderLayout.SOUTH);
        frame.setContentPane(mainPanel);

        // 選單列
        frame.setJMenuBar(menuBar);
        buildMenus();

        // 右鍵選單 (共用編輯動作)
        buildPopupMenu();

        // 文本區事件
        text.addMouseListener(new MouseAdapter() {
            @Override public void mouseClicked(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) pop.show(text, e.getX(), e.getY());
            }
        });
        text.addCaretListener(e -> dirty = true); // 內容變更標記

        frame.setVisible(true);
    }

    private void buildMenus() {
        // ---- 檔案選單 ----
        mFile = new JMenu("檔案(F)"); mFile.setMnemonic('F');
        miNew = newMenuItem("新建(N)", 'N', KeyEvent.VK_N, e -> newText());
        miOpen = newMenuItem("開啟(O)", 'O', KeyEvent.VK_O, e -> openText());
        miSave = newMenuItem("儲存(S)", 'S', KeyEvent.VK_S, e -> save());
        miSaveAs = newMenuItem("另存為...", 0, 0, e -> saveAs());
        miExit = newMenuItem("結束(Q)", 'Q', KeyEvent.VK_Q, e -> close());
        mFile.add(miNew); mFile.add(miOpen); mFile.add(miSave); mFile.add(miSaveAs);
        mFile.addSeparator(); mFile.add(miExit);

        // ---- 編輯選單 ----
        mEdit = new JMenu("編輯(E)"); mEdit.setMnemonic('E');
        miUndo = newMenuItem("撤銷(U)", 'U', KeyEvent.VK_U, e -> undo());
        miCut = newMenuItem("剪下(X)", 'X', KeyEvent.VK_X, e -> cut());
        miCopy = newMenuItem("複製(C)", 'C', KeyEvent.VK_C, e -> copy());
        miPaste = newMenuItem("貼上(V)", 'V', KeyEvent.VK_V, e -> paste());
        miDelete = newMenuItem("刪除(D)", 'D', KeyEvent.VK_D, e -> delete());
        miFind = newMenuItem("尋找(F)", 'F', KeyEvent.VK_F, e -> find());
        miReplace = newMenuItem("取代(R)", 'R', KeyEvent.VK_R, e -> replace());
        miSelectAll = newMenuItem("全選(A)", 'A', KeyEvent.VK_A, e -> selectAll());
        miTimeDate = newMenuItem("時間/日期(T)", 'T', KeyEvent.VK_T, e -> insertTimeDate());
        mEdit.add(miUndo); mEdit.addSeparator();
        mEdit.add(miCut); mEdit.add(miCopy); mEdit.add(miPaste); mEdit.add(miDelete);
        mEdit.addSeparator(); mEdit.add(miFind); mEdit.add(miReplace);
        mEdit.addSeparator(); mEdit.add(miSelectAll); mEdit.add(miTimeDate);

        // ---- 格式選單 ----
        mFormat = new JMenu("格式(O)"); mFormat.setMnemonic('O');
        miWordWrap = new JCheckBoxMenuItem("自動換行(W)");
        miWordWrap.addActionListener(e -> text.setLineWrap(miWordWrap.isSelected()));
        miFont = newMenuItem("字體...", 0, 0, e -> chooseFont());
        miColor = newMenuItem("顏色...", 0, 0, e -> chooseColor());
        mFormat.add(miWordWrap); mFormat.addSeparator(); mFormat.add(miFont); mFormat.add(miColor);

        // ---- 說明選單 ----
        mHelp = new JMenu("說明(H)"); mHelp.setMnemonic('H');
        miAbout = newMenuItem("關於作者(A)", 'A', KeyEvent.VK_A, e -> showAbout());
        mHelp.add(miAbout);

        // 加入選單列
        menuBar.add(mFile); menuBar.add(mEdit); menuBar.add(mFormat); menuBar.add(mHelp);
    }

    private void buildPopupMenu() {
        pop.add(new JMenuItem(new DefaultEditorKit.CutAction()));
        pop.add(new JMenuItem(new DefaultEditorKit.CopyAction()));
        pop.add(new JMenuItem(new DefaultEditorKit.PasteAction()));
        pop.addSeparator();
        pop.add(new JMenuItem("全選", e -> selectAll()));
        text.setComponentPopupMenu(pop);
    }

    // 快速建立帶快捷鍵的 JMenuItem
    private JMenuItem newMenuItem(String text, char mnemonic, int acceleratorKey, ActionListener listener) {
        JMenuItem mi = new JMenuItem(text);
        if (mnemonic != 0) mi.setMnemonic(mnemonic);
        if (acceleratorKey != 0) mi.setAccelerator(KeyStroke.getKeyStroke(acceleratorKey, Event.CTRL_MASK));
        mi.addActionListener(listener);
        return mi;
    }

    // ---- 佔位方法 (實作見下篇) ----
    private void newText() { /* 清空 textArea, filename="", dirty=false */ }
    private void openText() { /* JFileChooser 讀檔 */ }
    private void save() { /* 若 filename 空則 saveAs 否則寫檔 */ }
    private void saveAs() { /* JFileChooser 存檔 */ }
    private void close() { /* 檢查 dirty 確認儲存後 System.exit(0) */ }
    private void undo() { /* UndoManager.undo() */ }
    private void cut() { text.cut(); }
    private void copy() { text.copy(); }
    private void paste() { text.paste(); }
    private void delete() { text.replaceSelection(""); }
    private void find() { /* FindDialog */ }
    private void replace() { /* ReplaceDialog */ }
    private void selectAll() { text.selectAll(); }
    private void insertTimeDate() { text.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); }
    private void chooseFont() { /* JFontChooser */ }
    private void chooseColor() { /* JColorChooser */ }
    private void showAbout() { JOptionPane.showMessageDialog(frame, "記事本 v1.0\nAuthor: Jeason"); }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Jsb());
    }
}

設計亮點

  • Lambda 簡化事件註冊:JDK 8+ 以 Lambda 取代匿名內部類,程式碼簡潔 60% 以上。
  • 統一快捷鍵建立方法:newMenuItem() 封裝助憶鍵、加速鍵、監聽器,減少重複代碼。
  • 右鍵選單複用 DefaultEditorKit:剪貼簿動作無需自寫,直接採用 Swing 內建 Action。
  • 狀態集中管理:dirty、filename 單一來源,避免多處不同步。
  • 關閉流程可控:DO_NOTHING_ON_CLOSE + WindowAdapter 統一委派 close() 處理儲存確認。

編譯與執行


javac jeason/Jsb.java
java jeason.Jsb

需 JDK 8 或以上 (Lambda、DefaultEditorKit Action 皆為標準 API)。

後續擴充方向

  1. 實作 UndoManager 完成無限級撤銷/重做 (下篇詳解)。
  2. 搜尋/取代對話框 (JDialog + JTextField + 選項核取方塊)。
  3. 字體/顏色選擇器整合 (JFontChooser 非標準,可自行封裝或用第三方)。
  4. 多標籤分頁 (JTabbedPane),每個分頁獨立 dirty/filename。
  5. 行號顯示、語法高亮 (採用 RSyntaxTextArea 等成熟元件)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved