我正在尝试在行和列中显示字符串。由于它们的长度不同,并且代表连续文本的一部分,所以我希望每个组件仅占用显示整个String所需的大小。
到目前为止,我设法将单个项目加载到列表中,限制行数并使它们水平包装。我现在写了一个自定义ListCellRenderer,因为我认为这可以解决我的问题,但是它并没有达到我希望的方式。属于每个项目的两个字符串既不居中也不显示在彼此上方(实际上,它们根本不可读,因为它们似乎是在单元格外部绘制的),并且它们的大小都相同。我究竟做错了什么?
这是我的渲染器的外观:
public class ElementRenderer extends JPanel implements ListCellRenderer<Element> {
private Element element;
@Override
public Component getListCellRendererComponent(JList<? extends Element> list, Element value, int index,
boolean isSelected, boolean cellHasFocus) {
element = (Element) value;
if (element.getTag().equals("N/A"))
setEnabled(false);
else
setEnabled(true);
if (isSelected)
setBorder(BorderFactory.createLoweredSoftBevelBorder());
else
setBorder(BorderFactory.createRaisedSoftBevelBorder());
return this;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!isEnabled())
setBackground(Color.GRAY);
String word = element.getWord();
String tag = element.getTag();
FontMetrics fm = getFontMetrics(DataManager.getCurrentFont());
Rectangle bounds = getVisibleRect();
int y = bounds.y + ((bounds.height - 2*fm.getHeight())/2) + fm.getAscent();
g.drawString(word, bounds.x + (bounds.width - fm.stringWidth(word))/2, y);
g.drawString(tag, bounds.x + (bounds.width - fm.stringWidth(tag))/2, y + fm.getHeight());
}
@Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(DataManager.getCurrentFont());
int wordwidth = fm.stringWidth(element.getWord());
int tagwidth = fm.stringWidth(element.getTag());
if (tagwidth > wordwidth)
wordwidth = tagwidth;
return new Dimension(17+wordwidth, 3+fm.getHeight()*2);
}
最佳答案
在不弄乱JList
的LayoutManager
或ListUI
的情况下,我能找到的最简单的解决方案的确是创建自定义的ListCellRenderer
,但是具有以下逻辑:
自定义ListCellRenderer
是其中包含JPanel
的DefaultListCellRenderer
。
自定义ListCellRenderer
作为JPanel
将填充整个单元格空间。DefaultListCellRenderer
将位于我们的自定义ListCellRenderer
内部。我们可以通过将LayoutManager
的JPanel
设置为GridBagLayout
来实现。由于将仅添加单个组件(即DefaultListCellRenderer
是JLabel
),因此它将居中。
遵循示例代码:
import java.awt.Component;
import java.awt.GridBagLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
public class Main {
public static class DynamicWidthListCellRenderer extends JPanel implements ListCellRenderer {
private final DefaultListCellRenderer delegate;
public DynamicWidthListCellRenderer() {
super(new GridBagLayout());
delegate = new DefaultListCellRenderer();
super.add(delegate);
}
@Override
public Component getListCellRendererComponent(final JList list,
final Object value,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
//super.setBackground(delegate.getBackground()); //Test this out also...
return this;
}
}
public static void main(final String[] args) {
final JList<String> list = new JList<>(new String[]{"abc", "abcdefghijklmnop", "abcdefg", "a"});
list.setCellRenderer(new DynamicWidthListCellRenderer());
final JFrame frame = new JFrame("List variable width cells");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(list);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
以及示例屏幕截图(具有选定的元素):
关于java - 有没有办法使JList的每个项目都具有不同的宽度?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56684718/