Search code examples
javaswingjlistimageicon

Images not visible in JList


I'm writing a little photo application (asked some questions before) and I have one problem which I cannot resolve. The idea is that there are two sections: the upper one is for an overview (using thumbnails) and the lower one shows the selected image in it's full size. I cannot use ImageIO (required by my lecturer).

I'm using a JList for the overview but most images are not visible. I chose a folder with about 20 images and only 2 show up. And one of them isn't even centered.

For some reason, if I delete those lines:

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

One image shows up that wasn't visible before, but now the other two disappear.

This is my code:

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

Solution

  • Your problem is because of the way you're scaling your images.

    I'm not exactly sure why but I guess it has something to do with the BufferedImage#createGraphics() call and that I was able to reproduce the problem with .jpg images while .png files were correctly painted.

    However if you scale your images instead of converting them to a BufferedImage and getting a new ImageIcon from it, you get the correct output:

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

    This is the folder I used to test:

    enter image description here

    And the outputs with your code and mine:

    enter image description here enter image description here


    Important notes

    And as as a recommendation don't make a window that big if all you're using is that little bar above. If you're adding something else below, then it's ok but for now it's not that "user friendly" (IMHO). Instead of JFrame#setSize() you could try using JFrame#pack() method so your frame resizes to it's preferred size.

    Some other things I noted in your program:

    1. You're not placing it inside the Event Dispatch Thread (EDT) which is dangerous since your application won't be Thread safe that way. You can change that if you change your main method as follows:

      public static void main(String argS[]) {
          SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                  PVE pv = new PVE();
              }
          });
      }
      
    2. You're setting the JScrollPane preferred size, instead you should override its getPreferredSize() method, see Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing? (YES)

    3. You're extending JFrame, you should instead create an instance of it unless you're overriding one of its methods (and you're not, so don't do it) or you have any good reason to do it. If you need to extend a Container you should extend JPanel instead, as JFrame is a rigid container which cannot be placed inside another one. See this question and this one.

    I think I'm not missing anything, and hope this helps