图像在 JList 中不可见

Images not visible in JList

我正在写一个小照片应用程序(之前问过一些问题),但我有一个问题无法解决。这个想法是有两个部分:上面的部分用于概述(使用缩略图),下面的部分以全尺寸显示所选图像。我不能使用 ImageIO(我的讲师要求)。

我正在使用 JList 进行概览,但大多数图像不可见。我选择了一个包含大约 20 张图像的文件夹,但只显示了 2 张。其中一个甚至没有居中。

出于某种原因,如果我删除这些行:

 thumbnaillist.setFixedCellWidth(thumbW);
 thumbnaillist.setFixedCellHeight(thumbH);

一个图像出现了,之前不可见,但现在另外两个消失了。

这是我的代码:

public class PVE extends JFrame {

    private JFileChooser fileChoose;

    //MenuBar
    private JMenuBar menubar;
    private JMenu file;
    private JMenuItem openFolder;
    private JMenuItem exit;

    //Thumbnails
    private JList thumbnaillist;
    private DefaultListModel<ImageIcon> listmodel;
    private JScrollPane tscroll;
    private ImageIcon thumbs;
    private int thumbW = 100;
    private int thumbH = 100;

    //for full size view
    private JPanel imgview;

    public PVE() {
        setLayout(new BorderLayout());

        //MenuBar
        menubar = new JMenuBar();
        file = new JMenu("File");
        openFolder = new JMenuItem("Open folder...");
        exit = new JMenuItem("Quit");
        file.add(openFolder);
        file.addSeparator();
        file.add(exit);
        menubar.add(file);
        setJMenuBar(menubar);

        fileChoose = new JFileChooser();

        openFolder.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                fileChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                fileChoose.showOpenDialog(null);
                File chosenDir = fileChoose.getSelectedFile();
                loadToThumbView(chosenDir);
            }
        });

        //Thumbnail view
        listmodel = new DefaultListModel();
        thumbnaillist = new JList(listmodel);
        thumbnaillist.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        thumbnaillist.setFixedCellWidth(thumbW);
        thumbnaillist.setFixedCellHeight(thumbH);
        thumbnaillist.setVisibleRowCount(1);
        tscroll = new JScrollPane(thumbnaillist, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        tscroll.setPreferredSize(new Dimension(0, 100));
        add(tscroll, "North");

        //for full size view
        imgview = new JPanel();
        imgview.setBackground(Color.decode("#f7f7f7"));
        add(imgview, "Center");

        setTitle("Photo Viewer");
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception e) {

        }

        setSize(700, 700);
        setLocation(200, 200);
        setVisible(true);

    }

    public void loadToThumbView(File folder) {
        listmodel.removeAllElements();
        File[] imgpaths = folder.listFiles();
        for (int j = 0; j < imgpaths.length; j++) {
            listmodel.addElement(resizeToThumbnail(new ImageIcon(imgpaths[j].toString())));
        }
    }

    public ImageIcon resizeToThumbnail(ImageIcon icon) {
        Image img = icon.getImage();
        BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics g = bf.createGraphics();
        g.drawImage(img, 0, 0, thumbW, thumbH, null);
        ImageIcon kB = new ImageIcon(bf);
        return kB;
    }

    public static void main(String argv[]) {
        PVE pv = new PVE();
    }
}

您的问题是因为您缩放图像的方式。

我不确定为什么,但我想这与 BufferedImage#createGraphics() 调用有关,并且我能够在 .png 时使用 .jpg 图像重现该问题文件已正确绘制。

但是,如果您缩放图像而不是将它们转换为 BufferedImage 并从中获取新的 ImageIcon,您将得到正确的输出:

public ImageIcon resizeToThumbnail(ImageIcon icon) {
    Image img = icon.getImage();
    Image scaled = img.getScaledInstance(thumbW, thumbH, Image.SCALE_SMOOTH);
    return new ImageIcon(scaled);
}

这是我用来测试的文件夹:

你的代码和我的代码的输出:


重要提示

作为建议,如果您使用的只是上面那个小栏,则不要将 window 设置得那么大。如果您要在下面添加其他内容,那没关系,但现在还不是 "user friendly"(恕我直言)。而不是 JFrame#setSize() you could try using JFrame#pack() 方法,因此您的框架会调整到它的首选大小。

我在你的程序中注意到的其他一些事情:

  1. 您没有将它放在 Event Dispatch Thread (EDT) 中,这很危险,因为那样您的应用程序将不会是线程安全的。如果您按如下方式更改 main 方法,则可以更改它:

    public static void main(String argS[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                PVE pv = new PVE();
            }
        });
    }
    
  2. 您正在设置 JScrollPane 首选大小,您应该覆盖其 getPreferredSize() 方法,请参阅 Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing?(是)

  3. 您正在扩展 JFrame,您应该改为创建它的一个实例,除非您要覆盖它的其中一个方法(而您没有,所以不要这样做) 或者您有充分的理由这样做。如果您需要扩展 Container,您应该扩展 JPanel,因为 JFrame 是一个刚性容器,不能放在另一个容器中。见 this question and this one.

我想我没有遗漏任何东西,希望这对您有所帮助

您的“缩放”图像实际上是与原始图像相同大小的图像,但除了在左上角绘制的缩放版本之外是空白的。在每个渲染单元格中,左上角都被剪掉了(至少对于我测试过的有点大的图像)。

需要使用缩略图大小而不是原始图像的大小创建缩放后的图像。意思是,改变这个:

BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

对此:

BufferedImage bf = new BufferedImage(thumbW, thumbH, BufferedImage.TYPE_INT_ARGB);