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

Swing 組件實戰:JList 動態增刪與單選模式

     編輯:Java 程式設計入門

功能描述

展示可動態增刪的列表組件:

  • 初始預置 6 條人名數據
  • 單選模式(SINGLE_SELECTION),默認選中首項
  • 可見 5 行,超出自動顯示滾動條
  • 底部輸入框 +「添加」按鈕:插入到選中項後(無選中則插入首位)
  • 「刪除」按鈕:移除選中項,自動選中相鄰項
  • 重名檢測、空輸入攔截、按鈕啟用狀態聯動

核心架構:DefaultListModel + JList

DefaultListModel 作為可變數據模型,支援 addElement/insertElementAt/remove 等操作,JList 自動監聽模型變化並刷新視圖。

完整實現代碼

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class ListDemo extends JPanel implements ListSelectionListener {
    private JList list;
    private DefaultListModel model;
    private JButton addBtn, removeBtn;
    private JTextField inputField;

    public ListDemo() {
        super(new BorderLayout());

        // 1. 數據模型與初始數據
        model = new DefaultListModel<>();
        for (String name : new String[]{
            "Alan Sommerer", "Alison Huml", "Kathy Walrath",
            "Lisa Friendly", "Mary Campione", "Sharon Zakhour"
        }) model.addElement(name);

        // 2. JList 配置
        list = new JList<>(model);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        list.addListSelectionListener(this);
        list.setVisibleRowCount(5);
        JScrollPane scrollPane = new JScrollPane(list);

        // 3. 底部操作區
        addBtn = new JButton("添加");
        removeBtn = new JButton("刪除");
        inputField = new JTextField(10);

        // 添加邏輯:內部類 HireListener 實現 ActionListener + DocumentListener
        HireListener hireListener = new HireListener(addBtn);
        addBtn.addActionListener(hireListener);
        addBtn.setActionCommand("add");
        addBtn.setEnabled(false);
        inputField.addActionListener(hireListener);
        inputField.getDocument().addDocumentListener(hireListener);

        // 刪除邏輯
        removeBtn.addActionListener(new FireListener());
        removeBtn.setActionCommand("remove");
        removeBtn.setEnabled(false); // 初始有選中項,稍後在 valueChanged 中啟用

        // 底部面板佈局
        JPanel btnPanel = new JPanel();
        btnPanel.setLayout(new BoxLayout(btnPanel, BoxLayout.LINE_AXIS));
        btnPanel.add(removeBtn);
        btnPanel.add(Box.createHorizontalStrut(5));
        btnPanel.add(new JSeparator(SwingConstants.VERTICAL));
        btnPanel.add(Box.createHorizontalStrut(5));
        btnPanel.add(inputField);
        btnPanel.add(addBtn);
        btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        add(scrollPane, BorderLayout.CENTER);
        add(btnPanel, BorderLayout.PAGE_END);
    }

    // --- 刪除監聽 ---
    class FireListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            int idx = list.getSelectedIndex();
            model.remove(idx);
            int size = model.getSize();
            if (size == 0) {
                removeBtn.setEnabled(false);
            } else {
                if (idx >= size) idx = size - 1;
                list.setSelectedIndex(idx);
                list.ensureIndexIsVisible(idx);
            }
        }
    }

    // --- 添加監聽(含文本框狀態聯動) ---
    class HireListener implements ActionListener, DocumentListener {
        private JButton btn;
        private boolean alreadyEnabled = false;

        HireListener(JButton btn) { this.btn = btn; }

        @Override public void actionPerformed(ActionEvent e) {
            String name = inputField.getText().trim();
            if (name.isEmpty() || model.contains(name)) {
                Toolkit.getDefaultToolkit().beep();
                inputField.requestFocusInWindow();
                inputField.selectAll();
                return;
            }
            int idx = list.getSelectedIndex();
            if (idx == -1) idx = 0; else idx++;
            model.insertElementAt(name, idx);
            inputField.setText("");
            inputField.requestFocusInWindow();
            list.setSelectedIndex(idx);
            list.ensureIndexIsVisible(idx);
        }

        // DocumentListener:輸入框非空→啟用添加按鈕
        @Override public void insertUpdate(DocumentEvent e) { enableButton(); }
        @Override public void removeUpdate(DocumentEvent e) { handleEmpty(e); }
        @Override public void changedUpdate(DocumentEvent e) { if (!handleEmpty(e)) enableButton(); }

        private void enableButton() {
            if (!alreadyEnabled) { btn.setEnabled(true); alreadyEnabled = true; }
        }
        private boolean handleEmpty(DocumentEvent e) {
            if (e.getDocument().getLength() <= 0) {
                btn.setEnabled(false);
                alreadyEnabled = false;
                return true;
            }
            return false;
        }
    }

    // --- 列表選中狀態聯動刪除按鈕 ---
    @Override
    public void valueChanged(ListSelectionEvent e) {
        if (!e.getValueIsAdjusting()) {
            removeBtn.setEnabled(list.getSelectedIndex() != -1);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame("ListDemo");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setContentPane(new ListDemo());
            f.pack();
            f.setVisible(true);
        });
    }
}

關鍵設計模式

模式應用場景
Model-View 分離DefaultListModel 獨立管理數據,JList 專注渲染
事件委派ListSelectionListener、ActionListener、DocumentListener 分工明確
狀態機按鈕啟用/禁用由「有選中項」「輸入框非空」「無重名」三條件共同決定
即時反饋重名/空輸入 → 蜂鳴 + 全選 + 焦點回籠,引導用戶修正

擴展建議

  • 雙擊列表項進入編輯模式(需自定義 ListCellEditor)
  • 支持拖拽排序(DragSource/DropTarget)
  • 接入持久層:啟動加載/關閉保存至數據庫或配置文件
  • 遷移至 JavaFX ListView:綁定 ObservableList,聲明式綁定更簡潔
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved