Expand JList row height depending on content
Asked Answered
R

3

5

I have a simple problem which totally drives me crazy.

I have a JList, and would like its cells to expand depending on their content, which is text of variable length.

So I created a CustomCellRenderer like so:

@Override
public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus)
{
    final String text = (String) value;

    final JTextArea ta = new JTextArea();
    ta.setText(text);
    ta.setFont(new Font("Dialog", Font.PLAIN, (int) Theme.FONTSIZE_TEXT));
    ta.setForeground(Theme.FONTCOLOR_CONTENT);
    ta.setLineWrap(true);
    ta.setWrapStyleWord(true);
    ta.setColumns(0);
    ta.setBorder(BorderFactory.createEmptyBorder(10, Theme.PADDING, 0, 0));
    return ta;
}

but the cells are only one text line high and the rest of the JTextArea is cut off. If I add

ta.setPreferredSize(new Dimension(0, 70));

I get a row height of 70 and I can see more of the JTextArea's text, but still not everything.

Is there any way to make JList expand its cells so that the whole content of the JTextArea is displayed?

Relume answered 1/8, 2011 at 16:2 Comment(1)
An sscce might clarify the problem.Roseannroseanna
L
6

there are maybe easiest and nicest way, I think that JTable with one TableColumn (and without TableHeader)in all cases better as JList, here is your Render MacOX version

then output should be

enter image description here

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
//http://tips4java.wordpress.com/2008/10/26/text-utilities/
public class AutoWrapTest {

    public JComponent makeUI() {
        String[] columnNames = {" Text Area Cell Renderer "};
        Object[][] data = {
            {"123456789012345678901234567890"},
            {"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"},
            {"----------------------------------------------0"},
            {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddxdddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddddddx>>>>>>>>>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>ddddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "ddddddx>>>>>>>>>>>>>>>>>>>>>>>>>>|"},
            {"a|"},
            {">>>>>>>>bbbb>>>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddxdddddddddddddd123456789012345678901234567890dddddd"
                + "dddddddddddddddddddddddddddddddddddddx>>>>>>>>>>>>>>>>>>>>"
                + ">>>>>|"},
            {">>>>>>>>>>>>>dddddddddddddd123456789012345678901234567890dddddd"
                + "dddddddddddddddddddddddddddddddddddddxdddddddddddddd123456"
                + "789012345678901234567890dddddddddddddddddddddddddddddddddd"
                + "ddddd123456789012345678901234567890ddddx>>>>>>>>>>>>>>>>>>"
                + ">>>>>>>|"},};
        TableModel model = new DefaultTableModel(data, columnNames) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        JTable table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public void doLayout() {
                TableColumn col = getColumnModel().getColumn(0);
                for (int row = 0; row < getRowCount(); row++) {
                    Component c = prepareRenderer(col.getCellRenderer(), row, 0);
                    if (c instanceof JTextArea) {
                        JTextArea a = (JTextArea) c;
                        int h = getPreferredHeight(a) + getIntercellSpacing().height;
                        if (getRowHeight(row) != h) {
                            setRowHeight(row, h);
                        }
                    }
                }
                super.doLayout();
            }

            private int getPreferredHeight(JTextComponent c) {
                Insets insets = c.getInsets();
                View view = c.getUI().getRootView(c).getView(0);
                int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
                return preferredHeight + insets.top + insets.bottom;
            }
        };
        table.setEnabled(false);
        table.setShowGrid(false);
        table.setTableHeader(null);
        table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
        //table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane sp = new JScrollPane(table);
        sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        sp.setPreferredSize(new Dimension(250, 533));
        JPanel p = new JPanel(new BorderLayout());
        p.add(sp);
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new AutoWrapTest().makeUI());
        f.setLocation(100, 100);
        f.pack();
        f.setVisible(true);
    }
}

class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {

    private static final long serialVersionUID = 1L;
    private final Color evenColor = new Color(230, 240, 255);

    public TextAreaCellRenderer() {
        super();
        setLineWrap(true);
        setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (isSelected) {
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        } else {
            setForeground(table.getForeground());
            setBackground(table.getBackground());
            setBackground((row % 2 == 0) ? evenColor : getBackground());
        }
        setFont(table.getFont());
        setText((value == null) ? "" : value.toString());
        return this;
    }
}
Loraine answered 1/8, 2011 at 18:17 Comment(2)
Great. But this seems to only work for JTextArea (what I was asking for). Now what if I want to put the TextArea in a Panel and use the Panel as the cells component. How can I achieve, that the panel containing the Textarea still expands the height of the cell? Is there any chance to achieve a expandable cell height in general, no matter, what's the cells content.Relume
@Relume that about PreferredSize, doesn't matter if is there JTexArea of JPanel, be sure that JPanel would be better JComponents for that as plain JTextArea, for example #6356044Loraine
C
2

Try using JList's setFixedCellHeight() method.

Colchis answered 1/8, 2011 at 16:48 Comment(2)
This is 4 years ago but I ran into this same issue today and found that this answer changes all the jlists rows, not particular rows with particularly long or short content.Loverly
I don´t agree with your advice. Swing a is great front-framework where you can develop greats crossplatforms applications. Is a very mature framework, and very well documented. Its true there are some other crossplatforms options, like JavaFX, SWT, Qt... but I think Swing is a ver good option. For example IntelliJ (Android Studio) is a for me the best Commercial Swing application made ever, bringing a excelente user experience in every Operating System (Linux, Mac and Windows).Attitudinarian
K
2

Not sure if there is an elegant way. One way that I know works is as follows : In getListCellRendererComponent()

  • Use JLabel for the renderer
  • Convert the text in question to HTML and use some logic to insert <br> in to the text where desired.
  • Then set the text as text for the JLabel component and return.
Keratogenous answered 1/8, 2011 at 17:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.