JList - use a vertical scrollbar instead of horizontal with a vertical wrap orientation?
Asked Answered
B

3

8

I'm trying to place a JList inside of a JScrollPane and have it alphabetically list the entries in vertical columns like this:

A D G
B E H
C F 

However when the JList runs out of space to display more entries, I'd like the JScrollPane to scroll only in the vertical direction.

This works when I use VERTICAL_WRAP. However, it seems like when I use vertical wrap I get a horizontal scrollbar and when I use HORIZONTAL_WRAP I get the scrollbar I want, but the items get placed in an order that I don't like. Can I have my cake and eat it too? Here's a simple example of what I'm trying to do.

enter image description here

This is the closest I could get, but I'd like to be able to scroll vertically while maintaining the vertical alphabetical ordering.

public class ScrollListExample {
    static List<String> stringList = new ArrayList<String>();
    static {
        for (int i = 0; i < 500; i++) {
            stringList.add("test" + i);
        }
    }

    public static void main(final String[] args) {
        final JFrame frame = new JFrame();
        final Container contentPane = frame.getContentPane();
        final JList list = new JList(stringList.toArray());
        list.setLayoutOrientation(JList.VERTICAL_WRAP);
        list.setVisibleRowCount(0);
        final JScrollPane scrollPane = new JScrollPane(list);
        contentPane.add(scrollPane);
        frame.setPreferredSize(new Dimension(800, 400));
        frame.pack();
        frame.setVisible(true);
    }
}

One solution I've though of is: If the cell size is known I can create a component listener, and listen for a resize event. When that event is triggered I can calculate the desired row count in order to prevent horizontal scrolling. This just seems like a hack, and I'm not sure how it could work with variable sized text components.

Berceuse answered 2/2, 2012 at 19:33 Comment(6)
The reason you are getting HORIZONTAL scroll bar when using VERTICAL_WRAP is ` VERICAL_WRAP => Indicates "newspaper style" layout with the cells flowing vertically then horizontally.` SO, if cell will flow vertically and due to your dimension the output will get wrapped from bottom so than it will start filling horizontally.Therefor a horizontal scrollbar.Roemer
That makes sense, but most of my attempts to resize the inner components have not worked out as I would have expected. How would I force this to show a vertical scrollbar, and not a horizontal one? Is there a specific component I need to resize?Berceuse
@Lockyer: what is the exact output you need because you can get a vertical scrollbar using HORIZONTAL_WRAP as you have mentioned.What is that order you need.Roemer
I want the elements of my list to go vertically down the window in alphabetical order so that they're easier to scan visually. Just like Explorer does in windows when you select the "List" view.Berceuse
I would point out that the Explorer's List view uses a horizontal scroll bar, at least on Windows XP.Protozoology
Haha, whoops. I could have swore it was vertical, but I checked and you're right. Maybe it's not such a big deal if things scroll sideways after all! I think I'm just in the mindset of web design where horizontal scrolling is generally avoided. Still, I'd be curious if there's an elegant work around for achieving vertical scrolling, even if I don't use it in my production code now.Berceuse
A
2

I think your solution is just fine, and not a hack at all. Any built-in feature would have to do basically the same thing anyways.

Here's a modification to your example that does what you want.

public class ScrollListExample {
    static List<String> stringList = new ArrayList<String>();
    static {
        for (int i = 0; i < 500; i++) {
            stringList.add("test" + i);
        }
    }

    public static void main(final String[] args) {
        final JFrame frame = new JFrame();
        final Container contentPane = frame.getContentPane();
        final JList list = new JList(stringList.toArray());
        list.setLayoutOrientation(JList.VERTICAL_WRAP);
        final JScrollPane scrollPane = new JScrollPane(list);
        contentPane.add(scrollPane);
        frame.setPreferredSize(new Dimension(800, 400));
        frame.pack();

        list.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                fixRowCountForVisibleColumns(list);
            }
        });

        fixRowCountForVisibleColumns(list);
        frame.setVisible(true);
    }

    private static void fixRowCountForVisibleColumns(JList list) {
        int nCols = computeVisibleColumnCount(list);
        int nItems = list.getModel().getSize();

        // Compute the number of rows that will result in the desired number of
        // columns
        int nRows = nItems / nCols;
        if (nItems % nCols > 0) nRows++;
        list.setVisibleRowCount(nRows);
    }

    private static int computeVisibleColumnCount(JList list) {
        // It's assumed here that all cells have the same width. This method
        // could be modified if this assumption is false. If there was cell
        // padding, it would have to be accounted for here as well.
        int cellWidth = list.getCellBounds(0, 0).width;
        int width = list.getVisibleRect().width;
        return width / cellWidth;
    }
}
Arenaceous answered 3/2, 2012 at 18:38 Comment(1)
I was hoping there was something obvious I was missing, but it seems like this is probably the simplest solution.Berceuse
I
0

Is this what you're going for? (Might need to change the preferred size...)

public class ScrollListExample {
    static List<String> stringList = new ArrayList<String>();
    static {
        for (int i = 0; i < 500; i++) {
            stringList.add("test" + i);
        }
    }

    public static void main(final String[] args) {
        final JFrame frame = new JFrame();
        final Container contentPane = frame.getContentPane();
        final JList list = new JList(stringList.toArray());
        final JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
       scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        contentPane.add(scrollPane);
        frame.setPreferredSize(new Dimension(200,200));
        frame.pack();
        frame.setVisible(true);
    }
}
Irizarry answered 3/2, 2012 at 5:46 Comment(1)
No sorry, I should have explicitly stated that I want the items in the list to fill the available space. So when you expand the window horizontally an extra column should be added when possible.Berceuse
S
0

Brilliant Code @Kevin K... I suggest a small modification to avoid ArithmeticException (Divide by zero)

private int computeVisibleColumnCount(JList list) 
    {
        int cellWidth = list.getCellBounds(0, 0).width;
        int width = list.getVisibleRect().width;
        return width == 0 ? 1 : width / cellWidth;
    }
Slog answered 29/11, 2012 at 11:6 Comment(1)
This seems like it would be more at home in a comment instead of as a free standing answer.Berceuse

© 2022 - 2024 — McMap. All rights reserved.