Search code examples
javaswingmouseeventjlistlistcellrenderer

Using ListCellRenderers on selected entries


I'm using a ListCellRenderer to edit the appearance of entries in a JList. Once they are selected (by clicking them, this code is within a click event) I call the ListCellRenderer to change the color of the text. If they are selected again I want the text to return to the normal color. The problem I am having is that once I select a second entry the first entry goes back to its normal color. How can I keep selected entries the selected color until they are actually deselected? Here is the section where I actually call the function:

for(int i = 0; i < selectedEntries.size() - 1; i++){
    System.out.println("Inside the for loop at entry:" + i);
    if(selectedEntries.get(i).equals(selectedEntry)){
        selectedEntries.remove(i);
        removed = true;
        renderer.getListCellRendererComponent(logEntries, value, index, false, false);
        System.out.println("Duplicate Entry Removed From List");
    }
}

if(!removed){
    selectedEntries.add(selectedEntry);
    renderer.getListCellRendererComponent(logEntries, value, index, true, false);
}

Just for ease of interpretation selectedEntries is an ArrayList containing each selected entry's text.


Solution

  • Once they are selected (by clicking them, this code is within a click event) I call the ListCellRenderer to change the color of the text

    No, that's not how it should work, the ListCellRenderer will be called again (by the JList) and the isSelected parameter will be true, to which you would render the values differently

    The ListCellRenderer is responsible for rendering the entire state, selected or not selected.

    Have a look at Writing a Custom Cell Renderer for more details

    For example

    List of stuff

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.DefaultListModel;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                setLayout(new BorderLayout());
                DefaultListModel<String> model = new DefaultListModel<>();
                model.addElement("Apples");
                model.addElement("Bananas");
                model.addElement("Peachs");
                model.addElement("Pears");
                JList<String> listOfStrings = new JList<>(model);
                listOfStrings.setCellRenderer(new FancyPancyListCellRenderer());
                add(new JScrollPane(listOfStrings));
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
        }
    
        public static class FancyPancyListCellRenderer  extends DefaultListCellRenderer {
    
            protected static final Font SELECTED_FONT = new Font("Comic Sans MS", Font.PLAIN, 12);
    
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    
                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if (isSelected) {
                    setForeground(Color.YELLOW);
                    setFont(SELECTED_FONT);
                } else {
                    setFont(UIManager.getFont("Label.font"));
                }
                return this;
    
            }
    
        }
    
    }
    

    Also, MouseListener really isn't a suitable means by which to detect changes in the selection, what happens if the user selects rows using the keyboard? You should be using a ListSelectionListener instead (but not to correct this issue).

    Have a look at How to Write a List Selection Listener and How to Use Lists for more details