JList 单独大小的单元格 [英] JList Individually Sized Cells

查看:28
本文介绍了JList 单独大小的单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个水平排列的 JList.列表中的所有项目的大小都大不相同,默认情况下,渲染器将每个项目缩放到列表中最大项目的大小.我尝试按如下方式实现自定义渲染器,但列表中的每个项目都保持相同的大小.有什么建议吗?

以下是 ListCellRenderer:

package ui.wizards;导入 java.awt.Component;导入 java.awt.Dimension;导入 javax.swing.JLabel;导入 javax.swing.JList;导入 javax.swing.ListCellRenderer;导入 javax.swing.SwingConstants;公共类 WizHistoryCellRenderer 扩展 JLabel实现 ListCellRenderer;{private static final long serialVersionUID = -3650608268225337416L;JList列表;@覆盖公共组件 getListCellRendererComponent(JList 列表,字符串值、整数索引、布尔值 isSelected、布尔值 cellHasFocus){this.list = 列表;int width = this.getFontMetrics(this.getFont()).stringWidth((String) 值);整数高度 = 20;设置文本(值);如果(列表!= null){if (index == list.getSelectedIndex())显示选择();别的showUnselected();}setMaximumSize(new Dimension((int) (1.1 * width), height));setPreferredSize(new Dimension((int) (1.1 * width), height));setHorizo​​ntalAlignment(SwingConstants.CENTER);设置不透明(真);返回这个;}私有无效 showSelected(){setBackground(list.getSelectionBackground());setForeground(list.getSelectionForeground());}私有无效 showUnselected(){setBackground(list.getBackground());setForeground(list.getForeground());}}

解决方案

你需要三样东西:

  1. 每个单元格的比例因子.例如,您可以在列表的每个条目中添加 double 类型的比例因子变量.
  2. 自定义

    要自己运行它,只需选择至少一个索引,然后使用按钮进行操作.

    I have a horizontally arranged JList. All of the items in the list are of significantly different sizes, and by default the renderer scales each item to the size of the largest item in the list. I have attempted to implement a custom renderer as follows, but each item in the list remains the same size. Any advice?

    The following is the ListCellRenderer:

    package ui.wizards;
    
    import java.awt.Component;
    import java.awt.Dimension;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.ListCellRenderer;
    import javax.swing.SwingConstants;
    
    public class WizHistoryCellRenderer extends JLabel
            implements ListCellRenderer<String>
    {
        private static final long serialVersionUID = -3650608268225337416L;
        JList<? extends String> list;
    
        @Override
        public Component getListCellRendererComponent(JList<? extends String> list,
            String value, int index, boolean isSelected, boolean cellHasFocus)
        {
            this.list = list;
            int width = this.getFontMetrics(this.getFont())
                .stringWidth((String) value);
            int height = 20;
            setText(value);
    
            if (list != null)
            {
                if (index == list.getSelectedIndex())
                    showSelected();
                else
                    showUnselected();
            }
            setMaximumSize(new Dimension((int) (1.1 * width), height));
            setPreferredSize(new Dimension((int) (1.1 * width), height));
    
            setHorizontalAlignment(SwingConstants.CENTER);
            setOpaque(true);
    
            return this;
        }
    
        private void showSelected()
        {
            setBackground(list.getSelectionBackground());
            setForeground(list.getSelectionForeground());
        }
    
        private void showUnselected()
        {
            setBackground(list.getBackground());
            setForeground(list.getForeground());
        }
    }
    

    解决方案

    You will need 3 things:

    1. A scale factor for each individual cell. You may for example add a scale factor variable of type double in each entry of the list.
    2. A custom ListCellRenderer.
    3. Make the method BasicListUI#updateLayoutState() public.

    Follows self-contained code (read the comments for more info):

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import javax.swing.Icon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.ListCellRenderer;
    import javax.swing.plaf.basic.BasicListUI;
    
    public class JListIndipendentCellSizes {
    
        //Configuration constants:
        private static final int ICON_SIZE = 20;
        private static final double SCALE_STEP_SIZE = 0.125; //Smaller values of this makes zooming slower. Greater values makes zooming faster.
    
        //Simple Icon implementation for demonstration purposes.
        public static class TJIcon implements Icon {
            private final Color rectColor, ovalColor;
    
            public TJIcon(final Color rectColor, final Color ovalColor) {
                this.rectColor = rectColor;
                this.ovalColor = ovalColor;
            }
    
            @Override
            public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
                g.setColor(rectColor);
                g.fillRect(x, y, getIconWidth(), getIconHeight());
                g.setColor(ovalColor);
                g.fillOval(x, y, getIconWidth(), getIconHeight());
            }
    
            @Override public int getIconWidth() { return ICON_SIZE; }
            @Override public int getIconHeight() { return ICON_SIZE; }
        }
    
        //A simple list entry. Contains a text, an icon and (on top of them all) the scale factor:
        public static class TJListEntry {
            private final String text;
            private final Icon icon;
            private double scaleFactor;
    
            public TJListEntry(final String text,
                               final Icon icon) {
                this.text = text;
                this.icon = icon;
                scaleFactor = 1;
            }
    
            public String getText() {
                return text;
            }
    
            public Icon getIcon() {
                return icon;
            }
    
            public double getScaleFactor() {
                return scaleFactor;
            }
    
            public void zoomIn() {
                scaleFactor = scaleFactor + SCALE_STEP_SIZE;
            }
    
            public void zoomOut() {
                scaleFactor = Math.max(scaleFactor - SCALE_STEP_SIZE, SCALE_STEP_SIZE); //Do not allow underflow.
            }
    
            public void resetZoom() {
                scaleFactor = 1;
            }
        }
    
        public static class TJListCellRenderer extends JLabel implements ListCellRenderer<TJListEntry> {
            private double currentScaleFactor;
    
            public TJListCellRenderer() {
                //Ensure every pixel is painted starting from the top-left corner of the label:
                super.setVerticalAlignment(JLabel.TOP);
                super.setHorizontalAlignment(JLabel.LEFT);
                //We need to do this, because the scaling in paintComponent() is also relative to the top-left corner.
            }
    
            @Override
            public void paintComponent(final Graphics g) {
                //setRenderingHints here? Probably for ANTIALIAS...
                ((Graphics2D)g).scale(currentScaleFactor, currentScaleFactor); //Let's scale everything that is painted afterwards:
                super.paintComponent(g); //Let's paint the (scaled) JLabel!
            }
    
            @Override
            public Dimension getPreferredSize() {
                final Dimension superPrefDim = super.getPreferredSize(); //Handles automatically insets, icon size, text font, etc.
                final double w = superPrefDim.width * currentScaleFactor, //And we just scale the preferred size.
                             h = superPrefDim.height * currentScaleFactor; //And we just scale the preferred size.
                return new Dimension((int)w + 1, (int)h + 1); //Add one extra pixel to spare.
            }
    
            @Override
            public Component getListCellRendererComponent(final JList<? extends TJListEntry> list, final TJListEntry value, final int index, final boolean isSelected, final boolean cellHasFocus) {
    
                currentScaleFactor = value.getScaleFactor(); //Probably the most important step.
    
                setIcon(value.getIcon()); //Could be a loaded ImageIcon here (i.e. image)!
                setText(value.getText());
    
                if (isSelected) {
                    setBackground(list.getSelectionBackground());
                    setForeground(list.getSelectionForeground());
                } else {
                    setBackground(list.getBackground());
                    setForeground(list.getForeground());
                }
                setOpaque(true);
    
                return this;
            }
        }
    
        public static class TJListUI extends BasicListUI {
            @Override
            public void updateLayoutState() {
                super.updateLayoutState(); //Just make the following method public.
                /*Note: this is not really needed here:
                The method could remain protected, but in the case you want this
                code to be a bit more reusable, then you shall make it public.*/
            }
        }
    
        public static void main(final String[] args) {
            final TJListEntry[] entries = new TJListEntry[]{new TJListEntry("This is a sample text.", new TJIcon(Color.BLACK, Color.WHITE)),
                                                            new TJListEntry("This is a longer sample text.", new TJIcon(Color.GREEN, Color.RED)),
                                                            new TJListEntry("Small text", new TJIcon(Color.LIGHT_GRAY, Color.BLUE))};
    
            final TJListUI ui = new TJListUI();
    
            final JList<TJListEntry> list = new JList<>(entries);
            list.setUI(ui); //Important step! Without setting our UI, it won't work (at least as I have looked for).
            list.setCellRenderer(new TJListCellRenderer()); //Important step! Without setting our custom ListCellRenderer you will have to implement your own ListUI probably.
    
            final JScrollPane scroll = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    
            final JButton buttonZoomIn = new JButton("Zoom in selected cells"),
                          buttonZoomOut = new JButton("Zoom out selected cells"),
                          buttonResetZoom = new JButton("Reset zoom of selected cells");
    
            buttonZoomIn.addActionListener(e -> {
                for (final int i: list.getSelectedIndices())
                    list.getModel().getElementAt(i).zoomIn();
                ui.updateLayoutState(); //Read the preferred sizes from the cell renderer.
                list.revalidate(); //Update the JScrollPane.
                list.repaint(); //Repaint the list.
            });
    
            buttonZoomOut.addActionListener(e -> {
                for (final int i: list.getSelectedIndices())
                    list.getModel().getElementAt(i).zoomOut();
                ui.updateLayoutState(); //Read the preferred sizes from the cell renderer.
                list.revalidate(); //Update the JScrollPane.
                list.repaint(); //Repaint the list.
            });
    
            buttonResetZoom.addActionListener(e -> {
                for (final int i: list.getSelectedIndices())
                    list.getModel().getElementAt(i).resetZoom();
                ui.updateLayoutState(); //Read the preferred sizes from the cell renderer.
                list.revalidate(); //Update the JScrollPane.
                list.repaint(); //Repaint the list.
            });
    
            final JPanel buttons = new JPanel(); //FlowLayout.
            buttons.add(buttonZoomIn);
            buttons.add(buttonZoomOut);
            buttons.add(buttonResetZoom);
    
            final JPanel panel = new JPanel(new BorderLayout());
            panel.add(buttons, BorderLayout.PAGE_START);
            panel.add(scroll, BorderLayout.CENTER);
    
            final JFrame frame = new JFrame("Independent JList cell sizes demo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

    And a screenshot:

    To run it on your own, just select at least one index, and play with the buttons.

    这篇关于JList 单独大小的单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆