具有多行文本和动态高度的 Swing JList
我已经阅读/尝试过这些帖子,但这没有帮助:
我需要的是 ListCellRenderer
返回一个面板,左侧有一个图标,右侧有一个动态长度的文本(就像在任何论坛中一样:左侧是用户头像,右侧是帖子文本)。我不知道这些文本,因此我无法设置固定的单元格高度。此外,文本长度因列表单元格而异。因此,每个列表单元格都需要根据文本的长度有自己的高度。实际上这是一个非常常见的布局...但不适用于 Swing。单元格高度不会根据文本长度扩展。
我已经阅读了几乎所有关于 JList
中动态单元格高度和多行文本的帖子,但找不到解决方案。所以我决定参加一个小型的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;
}
}
}
I already read/tried these posts but that didn't help:
- Display multiple lines within a Jlist cell
- How to get multiline for a Jlist text?
- Problem displaying components of JList
What I need is a ListCellRenderer
which returns a panel with an icon on the left and a text of dynamic length on the right (like in any forum: on the left a user avatar, on the right the post text). The texts are NOT known to me, so I can't set a fixed cell height. Further, the text length differs from list cell to list cell. So every list cell needs its own height depending on the length of the text. Actually a really common layout ... but not for Swing. The cell height just doesn't expand according to the text length.
I already read almost any post out there about dynamic cell heights and multiline texts in JList
, but couldn't find a solution. So I decided to give a small SSCCE. Please give me a hint on how to achieve what I described or please fix my code if you think it's easy.
Thanks
Here is ths 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;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑1:哎呀 - 看到@Andrew的屏幕截图,意识到这没有按预期工作,文本实际上比显示的要长(忽略了内部评论“PENDING:不适用于JScrollPane中的JList” “;-) 如果我不能很快让它发挥作用,我会挖掘一下并删除这个答案。
编辑2:明白了 - 如下所示的渲染器实现是好的,罪魁祸首是 JList 偶尔小于最佳大小的缓存。 BasicListUI有两部分
使用下面渲染器的代码:
第一个答案(使用 JTextArea 作为渲染组件的渲染器实现)
TextArea 在调整大小方面有点棘手:它需要初始化为合理的值:
Edit 1: oops - seeing @Andrew's screenshot, realized that this isn't working as expected, the text is actually longer than shown with this (overlooked an internal comment "PENDING: not working for JList in JScrollPane" ;-) Will dig a bit and delete this answer if I can't make it work soon.
Edit 2: got it - the renderer implementation as shown below is okay, the culprit is the JList with its occasional less than optimal size caching. There are two parts of that
Code that uses the renderer below:
First answer (a renderer implementation which uses JTextArea as rendering component)
TextArea is a bit tricky in sizing: it needs to get initialized to something reasonable: