Search code examples
javaswingjlistsegments

Sectioned List in Java/Swing?


I have a list of items in a JList for the user to select. Since it's a lot of items (say, cities in states), I want to divide the list into sections. The section headings should not be selectable, though. So for my cities/states example, this might look like this:

  • State 1
    • City 1
    • City 2
    • City 3
  • State 2
    • City 4
    • City 5
    • City 6

It wouldn't be so difficult to write this myself by embedding JLists in a custom ListCellRenderer, but I'm wondering if there already is a class like that out there.


Solution

  • I see this question is already answered, but I noticed that Robert commented that he was hoping for an open source solution. I'd recommend using Glazed Lists' Separator list, the API for which you can be found here:

    http://publicobject.com/glazedlists/glazedlists-1.8.0/api/ca/odell/glazedlists/SeparatorList.html

    Here's some sample code that will produce a list of items grouped by their first letter:

    alt text http://img300.imageshack.us/img300/8977/separatorlist.png

    public class SeparatorListTest {
    
    private static Comparator<String> createComparator() {
        return new Comparator<String>() {
            public int compare(String stringOne, String stringTwo) {
                return stringOne.substring(0,1).compareTo(stringTwo.substring(0,1));
            }
        };
    }
    
    private static ListCellRenderer createListCellRenderer() {
        return new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    
                if (value instanceof SeparatorList.Separator) {
                    SeparatorList.Separator separator = (SeparatorList.Separator) value;
                    label.setText(separator.getGroup().get(0).toString().substring(0,1));
                    label.setFont(label.getFont().deriveFont(Font.BOLD));
                    label.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
                } else {
                    label.setFont(label.getFont().deriveFont(Font.PLAIN));
                    label.setBorder(BorderFactory.createEmptyBorder(0,15,0,0));
                }
    
                return label;
            }
        };
    }
    
    public static void main(String[] args) {
        EventList<String> rawList = GlazedLists.eventListOf(
                "apple", "appricot", "acorn", "blueberry", "coconut", "chesnut", "grape");
        SeparatorList<String> separatorList = 
                new SeparatorList<String>(rawList, createComparator(), 1, 1000);
    
        JList list = new JList(new EventListModel<String>(separatorList));
        list.setCellRenderer(createListCellRenderer());
        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setBorder(null);
    
        JFrame frame = new JFrame();
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200,200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    

    }