Reputation: 151
I have 2 JLists among which I'd like only one item to be selected. I created a separate program using only the code necessary to replicate the error: Main 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);
}
}
Staff 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());
}
}
I'm noticing however, sometimes when I switch between lists, instead of selecting the item, a blue box appears around the option. I tried to call getSelectionIndex() when this happens, and it returns -1. How do I make it select every time I click an item?
Upvotes: 0
Views: 431
Reputation: 285405
Your problem lies within your ListSelectionListener. First, let's create a much better and simpler MCVE, one that simplifie the code to only the essentials needed to reproduce the problem:
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());
}
}
Run this, and you'll see that the problem is reproduced -- the newly selected does not appropriately select the selected item. In addition, if you comment out the line, otherList.clearSelection();
, you'll see that the newly selected list will show the new selection just, fine, and so this line is at fault for messing up your desired behavior.
This can be fixed by limiting when the other list is cleared to only when the selected value is adjusting:
@Override
public void valueChanged(ListSelectionEvent e) {
// otherList.clearSelection();
if (e.getValueIsAdjusting()) {
otherList.clearSelection();
}
}
Why does this work? I honestly can't say for sure, but I do know that this will clear the other list's selection before the new list's item is being selected, and so it works. Also, you'll want to extract the selected value only when the value is not adjusting and so will need an if / else block as shown below:
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());
}
}
Upvotes: 2