Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JList单个大小的单元格_Java_Swing - Fatal编程技术网

Java JList单个大小的单元格

Java JList单个大小的单元格,java,swing,Java,Swing,我有一个水平排列的列表。列表中的所有项的大小都明显不同,默认情况下,渲染器会将每个项缩放到列表中最大项的大小。我试图实现如下自定义渲染器,但列表中的每个项目都保持相同的大小。有什么建议吗 以下是ListCellRenderer: package ui.wizards; import java.awt.Component; import java.awt.Dimension; import javax.swing.JLabel; import javax.swing.JList; import

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

以下是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());
    }
}

尝试调用JList方法setFixedCellHeight,参数为-1。这会导致JList在绘制列表项时使用任何自定义渲染器返回的首选高度。

我认为您可以尝试将javax.swing.plaf.basic.BasicListUI子类化,并覆盖受保护的void paintCellGraphics g、int row、矩形rowBounds、ListCellRenderer cellRenderer、ListModel dataModel、ListSelectionModel selModel、,int leadIndex和其他一些执行单元大小计算的方法


然后使用JList.setUIListUI应用自定义UI。UI负责使用ListCellRenders绘制JList。请原谅,我没有提供一个完整的示例,因为调整自定义绘图过程的各个方面可能需要大量的工作。

您需要3件事:

每个单元的比例因子。例如,您可以在列表的每个条目中添加一个double类型的比例因子变量。 习俗。 公开该方法。 遵循自包含的代码阅读注释了解更多信息:

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);
    }
}
和屏幕截图:


要自己运行它,只需选择至少一个索引,然后使用按钮即可。

谢谢您的提示。如果我能让它工作,我会发布调整。我在调用setListCellRenderer之前和之后都尝试调用setFixedCellHeight-1和setFixedCellWidth-1,但都没有任何效果。