Swing JList具有多行文本和动态高度

我已经阅读/试过这些post,但这没有帮助:

  • 在Jlist单元格中显示多行
  • 如何获取Jlist文本的多行?
  • 显示JList组件的问题

我需要的是一个ListCellRenderer ,它返回一个左侧带有图标的面板和右侧的动态长度文本(就像在任何论坛中一样:左边是用户头像,右边是post文本)。 这些文本为我所知,所以我无法设置固定的单元格高度。 此外,文本长度不同于列表单元格到列表单元格。 因此,每个列表单元格都需要自己的高度,具体取决于文本的长度。 实际上是一个非常常见的布局……但不适用于Swing。 单元格高度不会根据文本长度扩展。

我已经阅读了几乎所有有关JList动态单元格高度和多行文本的post,但找不到解决方案。 所以我决定给一个小型的SSCCE。 请告诉我如何实现我所描述的内容,或者如果您认为这很容易,请修改我的代码。

谢谢

这是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; } } } 

编辑1 :oops – 看到@Andrew的屏幕截图,意识到这没有按预期工作,文本实际上比显示的更长(忽略内部评论“PENDING:不适用于JScrollPane中的JList”;-)会挖一个如果我不能尽快使用它,请删除此答案。

编辑2 :得到它 – 如下所示的渲染器实现是可以的,罪魁祸首是JList,其偶尔不是最佳大小缓存。 这有两个部分

  • BasicListUI没有考虑到调整列表大小可能需要清除内部大小(实际行高)缓存,应用程序代码必须强制它这样做,在ComponentListener中使用fi
  • list的trackViewportWidth的Scrollable实现包含阻碍该区域的逻辑(导致该区域的循环拉伸直到它是单行),子类返回true。

使用以下渲染器的代码:

  final JList list = new JList(model) { /** * @inherited 

*/ @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));

第一个答案 (使用JTextArea作为渲染组件的渲染器实现)

TextArea在resize时有点棘手:它需要初始化为合理的东西:

 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; } } 

多行列表

 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 = ""; 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; } } } 
Interesting Posts