简体   繁体   中英

How do I wrap contents in a JList?

I have a JList that shows a list of files (with icons). I'm using DefaultListCellRenderer to accomplish this.

However, I would only like it to show 3 columns, but its showing more. I don't want the user to have to scroll horrizontally, only vertically. How can I do that? I'm fairly new to Java.

This is my code so far:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
import java.io.FileFilter;

import javax.swing.DefaultListCellRenderer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileSystemView;

public class StartMeUpBaby extends JFrame {

    public StartMeUpBaby() {

        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("TESTING");

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new GridBagLayout());

        File f = new File(System.getProperty("user.home"));

        JList<File> results = new JList<File>(f.listFiles(new FileFilter() {

            public boolean accept(File file) {

                String name = file.getName().toLowerCase();
                return name.length() < 20;

            }

        }));

        results.setCellRenderer(new DefaultListCellRenderer() {

            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {

                Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                JLabel label = (JLabel)component;
                File file = (File)value;

                label.setText(file.getName());
                label.setIcon(FileSystemView.getFileSystemView().getSystemIcon(file));
                label.setBorder(new EmptyBorder(3, 3, 3, 3));

                return label;

            }

        });

        results.setLayoutOrientation(JList.HORIZONTAL_WRAP);

        JScrollPane scrollPane = new JScrollPane(results, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setPreferredSize(new Dimension(408, 100));

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = 0;

        gbc.gridwidth = 3;
        gbc.gridheight = 2;

        gbc.weightx = 100;
        gbc.weighty = 100;

        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;

        gbc.insets = new Insets(5, 5, 5, 5);

        mainPanel.add(scrollPane, gbc);

        this.add(mainPanel);
        this.pack();
        this.setVisible(true);

    }

    public static void main(String[] args) {

        new StartMeUpBaby();

    }

}

I have the preferred size set to only showing 3 columns, however if you adjust the window (make it bigger) you can see that the columns continue on.

From the documentation of JList.setLayoutOrientation :

HORIZONTAL_WRAP - Cells are layed out horizontally, wrapping to a new row as necessary. If the visibleRowCount property is less than or equal to zero, wrapping is determined by the width of the list; otherwise wrapping is done in such a way as to ensure visibleRowCount rows in the list.

Therefore, you can solve your problem by adding this:

results.setVisibleRowCount(0);

However, your JScrollPane size ( setPreferredSize(new Dimension(488, 100)) ) is arbitrary. The size needed to show three columns will depend on the file names displayed, and on visual attributes like the JList's font. If even one fairly long file name is present, the cells will all be wider, and your size may not be sufficient.

To be completely robust, you will need to compute the preferred size based on the rendering of each file:

File f = new File(System.getProperty("user.home"));

File[] files = f.listFiles(new FileFilter() {

    public boolean accept(File file) {

        String name = file.getName().toLowerCase();
        return name.length() < 20;

    }

});

JList<File> results = new JList<File>(files) {
    private Dimension maxCellSize = new Dimension();

    @Override
    public void addNotify() {
        super.addNotify();
        recomputeMaxCellSize();
    }

    private void recomputeMaxCellSize() {
        ListCellRenderer<? super File> renderer = getCellRenderer();
        if (renderer == null) {
            return;
        }

        int fixedWidth = getFixedCellWidth();
        int fixedHeight = getFixedCellHeight();

        Rectangle maxCellBounds = new Rectangle();
        for (int i = getModel().getSize() - 1; i >= 0; i--) {
            Component c =
                renderer.getListCellRendererComponent(this,
                    getModel().getElementAt(i), i, false, false);
            Dimension cellSize = c.getPreferredSize();
            maxCellBounds.add(
                fixedWidth >= 0 ? fixedWidth : cellSize.width,
                fixedHeight >= 0 ? fixedHeight : cellSize.height);
        }

        maxCellSize = maxCellBounds.getSize();
    }

    @Override
    public Dimension getPreferredSize() {
        int count = getModel().getSize();
        int rows = count / 3 + (count % 3 == 0 ? 0 : 1);

        return new Dimension(maxCellSize.width * 3,
                             maxCellSize.height * rows);
    }

    @Override
    public Dimension getPreferredScrollableViewportSize() {
        int rows = getVisibleRowCount();
        if (rows <= 0) {
            rows = 4;
        }

        return new Dimension(maxCellSize.width * 3,
                             maxCellSize.height * rows);
    }

    private final ListDataListener modelListener = new ListDataListener() {
        @Override
        public void intervalAdded(ListDataEvent event) {
            recomputeMaxCellSize();
        }

        @Override
        public void intervalRemoved(ListDataEvent event) {
            recomputeMaxCellSize();
        }

        @Override
        public void contentsChanged(ListDataEvent event) {
            recomputeMaxCellSize();
        }
    };

    @Override
    public void setModel(ListModel<File> newModel) {
        getModel().removeListDataListener(modelListener);
        newModel.addListDataListener(modelListener);
        super.setModel(newModel);
        recomputeMaxCellSize();
    }

    @Override
    public void setCellRenderer(ListCellRenderer<? super File> renderer) {
        super.setCellRenderer(renderer);
        recomputeMaxCellSize();
    }

    @Override
    public void setFont(Font font) {
        super.setFont(font);
        recomputeMaxCellSize();
    }

    @Override
    public void setFixedCellWidth(int width) {
        super.setFixedCellWidth(width);
        recomputeMaxCellSize();
    }

    @Override
    public void setFixedCellHeight(int height) {
        super.setFixedCellHeight(height);
        recomputeMaxCellSize();
    }
};

results.setVisibleRowCount(0);

I figured it out after a bit of research through Java Documentation.

All I had to do was add this line:

results.setVisibleRowCount(-1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM