我正在尝试在行和列中显示字符串。由于它们的长度不同,并且代表连续文本的一部分,所以我希望每个组件仅占用显示整个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);
    }

最佳答案

在不弄乱JListLayoutManagerListUI的情况下,我能找到的最简单的解决方案的确是创建自定义的ListCellRenderer,但是具有以下逻辑:


自定义ListCellRenderer是其中包含JPanelDefaultListCellRenderer
自定义ListCellRenderer作为JPanel将填充整个单元格空间。
DefaultListCellRenderer将位于我们的自定义ListCellRenderer内部。我们可以通过将LayoutManagerJPanel设置为GridBagLayout来实现。由于将仅添加单个组件(即DefaultListCellRendererJLabel),因此它将居中。


遵循示例代码:

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的每个项目都具有不同的宽度?-LMLPHP

关于java - 有没有办法使JList的每个项目都具有不同的宽度?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56684718/

10-09 06:20