【问题标题】:Is there a way to make every item of a JList have different widths?有没有办法让 JList 的每个项目都有不同的宽度?
【发布时间】:2019-06-20 11:10:44
【问题描述】:

我正在尝试在行和列中显示字符串。由于它们的长度不同并且代表连续文本的一部分,我希望每个组件只占用显示整个字符串所需的大小。

到目前为止,我设法将单个项目加载到列表中,限制行数并使它们水平换行。我现在编写了一个自定义 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);
    }

【问题讨论】:

    标签: java swing jlist paintcomponent renderer


    【解决方案1】:

    好吧,我能找到的最简单的解决方案是创建一个自定义的ListCellRenderer,而不会弄乱JListLayoutManager,也不是它的ListUI,但具有以下逻辑:

    • 自定义ListCellRenderer 是一个JPanel,其中包含一个DefaultListCellRenderer
    • 自定义ListCellRenderer,作为JPanel,将填充整个单元格空间。
    • DefaultListCellRenderer 将在我们自定义的ListCellRenderer 中居中。我们可以通过将JPanelLayoutManager 设置为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);
        }
    }
    

    和示例截图(带有选定元素):

    【讨论】:

      猜你喜欢
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      相关资源
      最近更新 更多