JList getSelectionValue returns 清除后为空

JList getSelectionValue returns null after clear

我有 2 个 JList,其中我只想select编辑一个项目。我仅使用复制错误所需的代码创建了一个单独的程序: 主要 Class:

public class Main {

    public static void main(String[] args) {

        new Staff("John", "D", 123456);
        new Staff("Bob", "X", 123455);
        Staff.lookup("John","D").setActive(true);
        Staff.lookup("Bob","X").setActive(true);
        new Staff("Jerry","Smith",384938);
        new Staff("Bob","Hope",834802);

        new InstructorGUI(1);



    }

}

员工Class:

import java.util.ArrayList;
import java.util.List;


public class Staff{

    private String fName;
    private String lName;
    private int emtID;
    public static List<Staff> staffIndex = new ArrayList<>();
    public static ArrayList<Staff> activeStaffIndex = new ArrayList<>();

    Staff(String fName, String lName, int NJEMS) {
        this.fName = fName;
        this.lName = lName;
        staffIndex.add(this);
        emtID = NJEMS;
    }

    //Getters
    public int getEmtID() {
        return emtID;
    }
    public String getFirstName() {return fName; }
    public String getLastName() {return lName; }

    @Override
    public String toString() {
        return String.format("%s, %s", lName, fName);
    }

    //Lookups

    public static Staff lookup(String fName, String lName) {
        for (Staff s : staffIndex) {
            if (s.getFirstName().equalsIgnoreCase(fName) && s.getLastName().equalsIgnoreCase(lName)) {
                return s;
            }
        }
        return null;
    }

    //Setters
    public void setEmtID(int NJEMS) {
        emtID = NJEMS;
    }
    public void setFirstName(String s) {
        fName = s;
    }
    public void setLastName(String s) {
        lName = s;
    }

    //Removers
    public static void removeStaff(Staff s) {
        staffIndex.remove(s);
        activeStaffIndex.remove(s);
    }

    //Utilities
    public boolean isActive() {
        if(activeStaffIndex.contains(this)) {
            return true;
        } else {
            return false;
        }
    }
    public void setActive(Boolean b) {
        if (b) {
            if (!activeStaffIndex.contains(this)) {
                activeStaffIndex.add(this);
            }
        } else {
            if (activeStaffIndex.contains(this)) {
                activeStaffIndex.remove(this);
            }
        }
    }

}

InstructorGUI Class:

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashSet;

public class InstructorGUI extends JFrame {

    private static HashSet<InstructorGUI> instructorGUIIndex = new HashSet<>();
    private int identifier;

    private JList<Object> listSelected, selectedInstructors, unSelectedInstructors;

    public InstructorGUI(int id) {
        super("Instructor Editor");
        setSize(550, 250);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        identifier = id;

        boolean b = false;

        for (InstructorGUI i : instructorGUIIndex) {
            if (i.getIdentifier() == 1) {
                b = true;
            }
        }

        if (b) {
            InstructorGUI.lookup(1).dispose();
            instructorGUIIndex.remove(InstructorGUI.lookup(1));
        }

        instructorGUIIndex.add(this);

        JPanel container = new JPanel();
        JPanel middle = new JPanel();
        JPanel inputPanel = new JPanel();
        JPanel topButtons = new JPanel();
        JPanel left = new JPanel();
        JPanel centerButtons = new JPanel();
        JPanel right = new JPanel();
        JPanel footer = new JPanel();

        container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
        middle.setLayout(new BoxLayout(middle, BoxLayout.X_AXIS));
        inputPanel.setLayout(new FlowLayout());
        topButtons.setLayout(new FlowLayout());
        left.setLayout(new FlowLayout());
        centerButtons.setLayout(new BoxLayout(centerButtons, BoxLayout.Y_AXIS));
        right.setLayout(new FlowLayout());
        footer.setLayout(new FlowLayout());

        JLabel lNameLabel = new JLabel("Last");
        JLabel fNameLabel = new JLabel("First");
        JLabel emsIdLabel = new JLabel("EMS ID");

        JTextField lNameField = new JTextField(10);
        JTextField fNameField = new JTextField(10);
        JTextField emsIdField = new JTextField(10);

        selectedInstructors = new JList<>();
        unSelectedInstructors = new JList<>();


        JButton addInstructor = new JButton("Add");
        JButton editInstructor = new JButton("Edit");
        JButton removeInstructor = new JButton("Remove");

        JButton selectInstructor = new JButton("<-");
        JButton unSelectInstructor = new JButton("->");
        JButton selectAllInstructors = new JButton("<<--");
        JButton unSelectAllInstructors = new JButton("-->>");

        inputPanel.add(lNameLabel);
        inputPanel.add(lNameField);
        inputPanel.add(fNameLabel);
        inputPanel.add(fNameField);
        inputPanel.add(emsIdLabel);
        inputPanel.add(emsIdField);

        topButtons.add(addInstructor);
        topButtons.add(editInstructor);
        topButtons.add(removeInstructor);

        left.add(selectedInstructors);

        centerButtons.add(selectAllInstructors);
        centerButtons.add(selectInstructor);
        centerButtons.add(unSelectInstructor);
        centerButtons.add(unSelectAllInstructors);

        right.add(unSelectedInstructors);

        footer.add(new JLabel(""));

        JScrollPane x = new JScrollPane(selectedInstructors);
        JScrollPane y = new JScrollPane(unSelectedInstructors);

        x.setPreferredSize(new Dimension(100, 200));
        y.setPreferredSize(new Dimension(100, 200));

        middle.add(new JLabel(""));
        middle.add(x);
        middle.add(centerButtons);
        middle.add(y);
        middle.add(new JLabel(""));

        container.add(inputPanel);
        container.add(topButtons);
        container.add(middle);
        container.add(footer);

        update();

        selectedInstructors.addListSelectionListener(e -> {
            unSelectedInstructors.clearSelection();
            if(selectedInstructors.getSelectedValue() != null) {
                Staff s = Staff.lookup(selectedInstructors.getSelectedValue().toString().split(", ")[1], selectedInstructors.getSelectedValue().toString().split(", ")[0]);
                lNameField.setText(s.getLastName());
                fNameField.setText(s.getFirstName());
                emsIdField.setText(String.format("%s", s.getEmtID()));
                listSelected = selectedInstructors;
            }
        });
        unSelectedInstructors.addListSelectionListener(e -> {
            selectedInstructors.clearSelection();
            if (unSelectedInstructors.getSelectedValue() != null) {
                Staff s = Staff.lookup(unSelectedInstructors.getSelectedValue().toString().split(", ")[1], unSelectedInstructors.getSelectedValue().toString().split(", ")[0]);
                lNameField.setText(s.getLastName());
                fNameField.setText(s.getFirstName());
                emsIdField.setText(String.format("%s", s.getEmtID()));
                listSelected = unSelectedInstructors;
            }
        });

        setContentPane(container);
        setVisible(true);
        addInstructor.addActionListener(e -> {
            if(lNameField.getText().equalsIgnoreCase("") || fNameField.getText().equalsIgnoreCase("") || emsIdField.getText().equalsIgnoreCase("")) {
                return;
            }
            if(Integer.parseInt(emsIdField.getText()) < 300000 || Integer.parseInt(emsIdField.getText()) > 900000) {
                JOptionPane.showMessageDialog(null,"Please choose an EMS ID between 300000 and 900000.");
                return;
            }
            for(Staff s : Staff.staffIndex) {
                if(Integer.parseInt(emsIdField.getText()) == s.getEmtID()) {
                    JOptionPane.showMessageDialog(null, "EMS ID already taken.");
                    return;
                }
            }
            new Staff(fNameField.getText(),lNameField.getText(),Integer.parseInt(emsIdField.getText()));
            update();
        });
        editInstructor.addActionListener(e -> {
            if(lNameField.getText().equalsIgnoreCase("") || fNameField.getText().equalsIgnoreCase("") || emsIdField.getText().equalsIgnoreCase("")) {
                return;
            }
            if(Integer.parseInt(emsIdField.getText()) < 300000 || Integer.parseInt(emsIdField.getText()) > 900000) {
                JOptionPane.showMessageDialog(null,"Please choose an EMS ID between 300000 and 900000.");
                return;
            }
            for(Staff s : Staff.staffIndex) {
                if(Integer.parseInt(emsIdField.getText()) == s.getEmtID()) {
                    JOptionPane.showMessageDialog(null, "EMS ID already taken.");
                    return;
                }
            }
            Staff s = Staff.lookup(listSelected.getSelectedValue().toString().split(", ")[1],listSelected.getSelectedValue().toString().split(", ")[0]);
            if(!s.getFirstName().equalsIgnoreCase(fNameField.getText()) || !s.getLastName().equalsIgnoreCase(lNameField.getText()) || s.getEmtID() != Integer.parseInt(emsIdField.getText())) {
                s.setFirstName(fNameField.getText());
                s.setLastName(lNameField.getText());
                s.setEmtID(Integer.parseInt(emsIdField.getText()));
                update();
            }
        });
        removeInstructor.addActionListener(e -> {
            if(listSelected.getSelectedValue() != null) {
                Staff s = Staff.lookup(listSelected.getSelectedValue().toString().split(", ")[1],listSelected.getSelectedValue().toString().split(", ")[0]);
                Staff.removeStaff(s);
                update();
            }
        });
        selectInstructor.addActionListener(e -> {
            if(unSelectedInstructors.getSelectedValue() != null) {
                Staff s = Staff.lookup(unSelectedInstructors.getSelectedValue().toString().split(", ")[1], unSelectedInstructors.getSelectedValue().toString().split(", ")[0]);
                s.setActive(true);
                update();
            }
        });
        unSelectInstructor.addActionListener(e -> {
            if(selectedInstructors.getSelectedValue() != null) {
                Staff s = Staff.lookup(selectedInstructors.getSelectedValue().toString().split(", ")[1], selectedInstructors.getSelectedValue().toString().split(", ")[0]);
                s.setActive(false);
                update();
            }
        });
        selectAllInstructors.addActionListener(e -> {
            for(Staff s : Staff.staffIndex) {
                s.setActive(true);
            }
            update();
        });
        unSelectAllInstructors.addActionListener(e -> {
            for(Staff s : Staff.staffIndex) {
                s.setActive(false);
            }
            update();
        });
    }

    public int getIdentifier() {
        return identifier;
    }

    public static InstructorGUI lookup(int id) {
        for (InstructorGUI i : instructorGUIIndex) {
            if (i.getIdentifier() == id) {
                return i;
            }
        }
        return null;
    }

    public void update() {
        ArrayList<Staff> selected = new ArrayList<>();
        ArrayList<Staff> notSelected = new ArrayList<>();

        for (Staff s : Staff.staffIndex) {
            if (s.isActive()) {
                selected.add(s);
            } else {
                notSelected.add(s);
            }
        }

        selectedInstructors.removeAll();
        unSelectedInstructors.removeAll();
        selectedInstructors.setListData(selected.toArray());
        unSelectedInstructors.setListData(notSelected.toArray());


    }

}

然而,我注意到,有时当我在列表之间切换时,而不是 selecting 项目,选项周围会出现一个蓝色框。发生这种情况时,我尝试调用 getSelectionIndex(),它 returns -1。我如何在每次单击项目时都select?

您的问题出在您的 ListSelectionListener 中。首先,让我们创建一个更好更简单的 MCVE,将代码简化为仅重现问题所需的要素:

import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

@SuppressWarnings("serial")
public class Main2 extends JPanel {
    private JList<String> list1 = new JList<>(new String[] { "one", "two", "three" });
    private JList<String> list2 = new JList<>(new String[] { "hello", "goodbye", "yes" });

    public Main2() {
        list1.setName("list 1");
        list2.setName("list 2");
        list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        list1.addListSelectionListener(new MySelectionListener(list2));
        list2.addListSelectionListener(new MySelectionListener(list1));

        setLayout(new GridLayout(1, 0));
        add(new JScrollPane(list1));
        add(new JScrollPane(list2));
    }

    private class MySelectionListener implements ListSelectionListener {
        private JList<String> otherList;

        public MySelectionListener(JList<String> otherList) {
            this.otherList = otherList;
        }

        @Override
        public void valueChanged(ListSelectionEvent e) {
            otherList.clearSelection();
        }
    }

    private static void createAndShowGui() {
        Main2 mainPanel = new Main2();

        JFrame frame = new JFrame("Main2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

运行 这个,你会发现问题重现了——新 selected 没有适当地 select selected 项目。此外,如果您注释掉行 otherList.clearSelection();,您会看到新 selected 列表将显示新的 selection just, fine,因此此行位于搞砸你想要的行为是错误的。

这可以通过限制何时清除其他列表来解决,仅当 selected 值正在调整时:

@Override
public void valueChanged(ListSelectionEvent e) {
    // otherList.clearSelection();
    if (e.getValueIsAdjusting()) {
        otherList.clearSelection();
    }
}

为什么这样做?老实说,我不能肯定地说,但我知道这会在 select 编辑新列表的项目 select 之前清除其他列表的 selection ,所以它有效。此外,您需要仅在值未调整时提取 selected 值,因此需要一个 if / else 块,如下所示:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

@SuppressWarnings("serial")
public class Main2 extends JPanel {
    private JList<String> list1 = new JList<>(new String[] { "one", "two", "three" });
    private JList<String> list2 = new JList<>(new String[] { "hello", "goodbye", "yes" });
    private JTextField selectedItemTxtFld = new JTextField(10);

    public Main2() {
        list1.setName("list 1");
        list2.setName("list 2");
        list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        list1.addListSelectionListener(new MySelectionListener(list2));
        list2.addListSelectionListener(new MySelectionListener(list1));

        JPanel listPanel = new JPanel(new GridLayout(1, 0));
        listPanel.add(new JScrollPane(list1));
        listPanel.add(new JScrollPane(list2));

        JPanel topPanel = new JPanel();
        topPanel.add(new JLabel("Selection:"));
        topPanel.add(selectedItemTxtFld);

        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.PAGE_START);
        add(listPanel, BorderLayout.CENTER);
    }

    private class MySelectionListener implements ListSelectionListener {
        private JList<String> otherList;

        public MySelectionListener(JList<String> otherList) {
            this.otherList = otherList;
        }

        @Override
        public void valueChanged(ListSelectionEvent e) {
            // otherList.clearSelection();
            if (e.getValueIsAdjusting()) {
                otherList.clearSelection();
            } else {
                JList<String> thisList = (JList<String>) e.getSource();
                if (!thisList.isSelectionEmpty()) {
                    String selectedText = thisList.getSelectedValue().toString();
                    selectedItemTxtFld.setText(selectedText);
                }
            }
        }
    }

    private static void createAndShowGui() {
        Main2 mainPanel = new Main2();

        JFrame frame = new JFrame("Main2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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