uso usando setmodel para objetos modelo lista almacenar java swing jlist expand listcellrenderer

java - usando - Swing JList con texto multilínea y altura dinámica



usando un jlist para almacenar objetos (2)

Editar 1 : oops: al ver la captura de pantalla de @ Andrew, se dio cuenta de que esto no funcionaba como se esperaba, el texto es en realidad más largo que el mostrado con esto (se pasó por alto un comentario interno "PENDIENTE: no funciona para JList en JScrollPane" ;-) Cavará un mordí y borré esta respuesta si no puedo hacer que funcione pronto.

Edición 2 : lo obtuve: la implementación del renderizador como se muestra a continuación está bien, el culpable es el JList con su caché ocasional de tamaño inferior al óptimo. Hay dos partes de eso

  • BasicListUI no tiene en cuenta que el cambio de tamaño de la lista puede requerir la eliminación de la memoria caché de tamaño interno (en realidad, la altura de la fila), el código de la aplicación debe obligarlo a hacerlo, fi en un ComponentListener
  • La implementación desplegable de la lista de tracksViewportWidth contiene una lógica que se interpone en el camino (conduce a la extensión del bucle del área hasta que se trata de una sola línea), subclase para devolver verdadero.

Código que usa el procesador a continuación:

final JList list = new JList(model) { /** * @inherited <p> */ @Override public boolean getScrollableTracksViewportWidth() { return true; } }; list.setCellRenderer(new MyCellRenderer()); ComponentListener l = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { // next line possible if list is of type JXList // list.invalidateCellSizeCache(); // for core: force cache invalidation by temporarily setting fixed height list.setFixedCellHeight(10); list.setFixedCellHeight(-1); } }; list.addComponentListener(l); add(new JScrollPane(list));

Primera respuesta (una implementación del renderizador que usa JTextArea como componente de representación)

TextArea es un poco complicado en tamaño: necesita inicializarse a algo razonable:

public class MyCellRenderer implements ListCellRenderer { private JPanel p; private JPanel iconPanel; private JLabel l; private JTextArea ta; public MyCellRenderer() { p = new JPanel(); p.setLayout(new BorderLayout()); // icon iconPanel = new JPanel(new BorderLayout()); l = new JLabel("icon"); // <-- this will be an icon instead of a // text iconPanel.add(l, BorderLayout.NORTH); p.add(iconPanel, BorderLayout.WEST); // text ta = new JTextArea(); ta.setLineWrap(true); ta.setWrapStyleWord(true); p.add(ta, BorderLayout.CENTER); } @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus) { ta.setText((String) value); int width = list.getWidth(); // this is just to lure the ta''s internal sizing mechanism into action if (width > 0) ta.setSize(width, Short.MAX_VALUE); return p; } }

Ya leí / intenté estas publicaciones, pero eso no ayudó:

Lo que necesito es un ListCellRenderer que devuelva un panel con un icono a la izquierda y un texto de longitud dinámica a la derecha (como en cualquier foro: a la izquierda un avatar de usuario, a la derecha el texto de publicación). NO conozco los textos, por lo que no puedo establecer una altura de celda fija. Además, la longitud del texto difiere de la celda de la lista a la celda de la lista. Entonces, cada celda de la lista necesita su propia altura dependiendo de la longitud del texto. En realidad, un diseño muy común ... pero no para Swing. La altura de la celda simplemente no se expande según la longitud del texto.

Ya leí casi cualquier publicación sobre alturas de celda dinámicas y textos de JList en JList , pero no pude encontrar una solución. Entonces decidí dar un pequeño SSCCE. Por favor, dame una pista sobre cómo lograr lo que describí o arregla mi código si crees que es fácil.

Gracias

Aquí está este SSCCE:

public class MultiLineList extends JFrame { private static final long serialVersionUID = 1L; public static void main(final String[] args) { new MultiLineList(); } private MultiLineList() { setTitle("MultiLineList"); setSize(800, 450); setResizable(true); setVisible(true); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.getContentPane().setLayout(new BorderLayout()); final DefaultListModel model = new DefaultListModel(); model.addElement("This is a short text"); model.addElement("This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. "); model.addElement("This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. "); final JList list = new JList(model); list.setCellRenderer(new MyCellRenderer()); this.add(list); this.getContentPane().invalidate(); this.getContentPane().validate(); } public class MyCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus) { final String text = (String) value; //create panel final JPanel p = new JPanel(); p.setLayout(new BorderLayout()); //icon final JPanel IconPanel = new JPanel(new BorderLayout()); final JLabel l = new JLabel("icon"); //<-- this will be an icon instead of a text IconPanel.add(l, BorderLayout.NORTH); p.add(IconPanel, BorderLayout.WEST); //text final JTextArea ta = new JTextArea(); ta.setText(text); ta.setLineWrap(true); ta.setWrapStyleWord(true); p.add(ta, BorderLayout.CENTER); return p; } } }


import java.awt.*; import javax.swing.*; public class MultiLineList { private static final long serialVersionUID = 1L; public static void main(final String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new MultiLineList(); } }); } private MultiLineList() { JFrame f = new JFrame("MultiLineList"); f.setResizable(true); f.setVisible(true); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().setLayout(new BorderLayout()); final DefaultListModel model = new DefaultListModel(); model.addElement("This is a short text"); model.addElement("This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. "); model.addElement("This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. "); final JList list = new JList(model); list.setCellRenderer(new MyCellRenderer()); f.add(list); f.pack(); } public class MyCellRenderer extends DefaultListCellRenderer { final JPanel p = new JPanel(new BorderLayout()); final JPanel IconPanel = new JPanel(new BorderLayout()); final JLabel l = new JLabel("icon"); //<-- this will be an icon instead of a text final JLabel lt = new JLabel(); String pre = "<html><body style=''width: 200px;''>"; MyCellRenderer() { //icon IconPanel.add(l, BorderLayout.NORTH); p.add(IconPanel, BorderLayout.WEST); p.add(lt, BorderLayout.CENTER); //text } @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus) { final String text = (String) value; lt.setText(pre + text); return p; } } }