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

Java Swing 列表框動態增刪元素與數據回收完整實現

     編輯:Java 程式設計入門

場景痛點

雙列表框交互 (可選項 ←→ 已選項) 是典型 UI 模式。需求:

  1. 左側列表多選 → 點「>>」移入右側
  2. 右側列表多選 → 點「<<」移回左側
  3. 確定時獲取右側所有元素值 (如商品 ID 列表) 供業務使用

核心難點:JList 本身不存數據,需配合 ListModel;同步雙向移動時維護數據一致性;最終提取泛型數據並轉型。

架構設計

  • 視圖層:JScrollPane + JList (設置 SelectionMode.MULTIPLE_INTERVAL_SELECTION)
  • 模型層:兩個 DefaultListModel (左/右) + 一個 Vector (業務數據備份,動態擴容)
  • 控制層:按鈕事件中操作 Model 與 Vector 同步

完整可運行 Demo 代碼

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

public class DualListBoxDemo extends JFrame {
    // 左側:可選項
    private final DefaultListModel<String> leftModel = new DefaultListModel<>();
    private final JList<String> leftList = new JList<>(leftModel);
    // 右側:已選項
    private final DefaultListModel<String> rightModel = new DefaultListModel<>();
    private final JList<String> rightList = new JList<>(rightModel);
    // 業務數據備份 (與 rightModel 同步)
    private final Vector<String> selectedData = new Vector<>();

    public DualListBoxDemo() {
        setTitle("雙列表框動態增刪演示");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(600, 400);
        setLayout(new BorderLayout(10, 10));

        // 初始化左側數據
        String[] items = {"蘋果", "香蕉", "橙子", "葡萄", "西瓜", "草莓", "芒果", "鳳梨"};
        for (String s : items) leftModel.addElement(s);

        // 左側面板
        JPanel leftPanel = new JPanel(new BorderLayout());
        leftPanel.add(new JLabel("可選商品 (多選)"), BorderLayout.NORTH);
        leftList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        leftPanel.add(new JScrollPane(leftList), BorderLayout.CENTER);

        // 右側面板
        JPanel rightPanel = new JPanel(new BorderLayout());
        rightPanel.add(new JLabel("已選商品 (多選)"), BorderLayout.NORTH);
        rightList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        rightPanel.add(new JScrollPane(rightList), BorderLayout.CENTER);

        // 中間按鈕欄
        JPanel btnPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JButton btnAdd = new JButton(">>");
        JButton btnRemove = new JButton("<<");
        btnPanel.add(btnAdd);
        btnPanel.add(btnRemove);

        // 組裝主面板
        JPanel center = new JPanel(new GridLayout(1, 3, 10, 0));
        center.add(leftPanel);
        center.add(btnPanel);
        center.add(rightPanel);
        add(center, BorderLayout.CENTER);

        // 底部確定按鈕
        JButton btnConfirm = new JButton("確定獲取選中值");
        add(btnConfirm, BorderLayout.SOUTH);

        // ===== 事件邏輯 =====
        btnAdd.addActionListener(e -> moveSelected(leftList, leftModel, rightModel, selectedData, true));
        btnRemove.addActionListener(e -> moveSelected(rightList, rightModel, rightModel, selectedData, false));
        btnConfirm.addActionListener(e -> {
            String[] result = selectedData.toArray(new String[0]);
            JOptionPane.showMessageDialog(this, "已選商品 (" + result.length + "):\n" + String.join(", ", result));
            // 此處可將 result 傳給業務層
        });

        setLocationRelativeTo(null);
    }

    /**
     * 通用移動邏輯
     * @param sourceList 來源列表
     * @param sourceModel 來源模型
     * @param targetModel 目標模型 (右側模型)
     * @param dataVector 業務數據向量 (僅同步右側)
     * @param toRight true=左→右, false=右→左
     */
    private void moveSelected(JList<String> sourceList, DefaultListModel<String> sourceModel,
                              DefaultListModel<String> targetModel, Vector<String> dataVector, boolean toRight) {
        int[] indices = sourceList.getSelectedIndices();
        if (indices.length == 0) return;

        // 必須倒序刪除,避免索引錯位
        for (int i = indices.length - 1; i >= 0; i--) {
            String val = sourceModel.getElementAt(indices[i]);
            sourceModel.remove(indices[i]);
            targetModel.addElement(val);
            if (toRight) {
                dataVector.addElement(val); // 同步業務數據
            } else {
                dataVector.removeElement(val); // 移除業務數據
            }
        }
        sourceList.clearSelection();
    }

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

關鍵技術點解析

技術點說明
DefaultListModel可變列表模型,支援 addElement/removeElement/insertElementAt,自動觸發 JList 重繪
SelectionMode.MULTIPLE_INTERVAL_SELECTION支援 Ctrl/Shift 多選,getSelectedIndices() 返回所有選中索引
倒序遍歷刪除從最大索引向 0 刪除,防止前序刪除導致後序索引偏移
Vector 同步備份線程安全、動態擴容、toArray() 直接轉型為強類型數組
泛型 <String>編譯期類型安全,避免運行時 ClassCastException

進階擴展建議

  1. 自定義對象:將 String 替換為 Product 等領域對象,JList 配合 ListCellRenderer 顯示名稱,Vector<Product> 直接攜帶完整業務數據。
  2. 雙向同步優化:左側模型也可維護 Vector,實現真正的雙向數據綁定。
  3. 拖拽支持:實現 TransferHandler 支持鼠標拖拽移動,體驗更佳。
  4. 數據校驗:移入前檢查重複、數量上限、業務規則。

常見坑避雷

  • ❌ 直接操作 JList 不操作 Model → 界面不更新
  • ❌ 正序刪除多選項 → 索引錯位導致漏刪/錯刪
  • ❌ 忽略 Vector 與 Model 同步 → 確定時取不到最新數據
  • ❌ 未設置 SelectionMode → 默認單選,無法多選
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved