【问题标题】:Image not appearing in JFrame图像未出现在 JFrame 中
【发布时间】:2016-02-22 08:16:57
【问题描述】:

我正在尝试用 Java 制作幻灯片程序。可悲的是,图像没有出现在窗口中。不知道为什么……

我所知道的是一切运行顺利,没有发生错误(堆栈跟踪)。窗口出现,那里没有图像。

public class Slideshow implements ActionListener, Runnable {
private ArrayList<String> haveUsed = new ArrayList<>();
private JFrame settingsFrame, imageFrame;
private JTextField rootFolder, timeFrame, hiddenRootFolder, hiddenTimeFrame;
private JButton startSlideShow, addRootFolder;
private JLabel jLabel = null;
private ImageIcon imageIcon = null;
public void openSettingsFrame() {
    settingsFrame = new JFrame("Settings - Slideshow v1.0");
    settingsFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    settingsFrame.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    settingsFrame.setSize(400, 400);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.insets = new Insets(0, 0, 5, 0);
    hiddenRootFolder = new JTextField("Root Folder:");
    hiddenRootFolder.setEditable(false);
    hiddenRootFolder.setBackground(settingsFrame.getBackground());
    hiddenRootFolder.setBorder(BorderFactory.createLineBorder(settingsFrame.getBackground()));
    settingsFrame.add(hiddenRootFolder, gbc);

    gbc.gridx = 1;
    rootFolder = new JTextField("", 15);
    gbc.insets = new Insets(0, 0, 0, 5);
    rootFolder.setBackground(new Color(255, 255, 255));
    rootFolder.setEditable(false);
    //TODO: add mouse listener
    settingsFrame.add(rootFolder, gbc);

    gbc.gridx = 2;
    addRootFolder = new JButton("Add");
    addRootFolder.addActionListener(this);
    addRootFolder.setSize(80, 20);
    addRootFolder.setPreferredSize(new Dimension(60, 20));
    addRootFolder.setMinimumSize(new Dimension(60, 20));
    settingsFrame.add(addRootFolder, gbc);

    gbc.gridx = 0;
    gbc.gridy = 1;
    hiddenTimeFrame = new JTextField("Speed sec.:");
    gbc.insets = new Insets(0, 0, 5, 0);
    hiddenTimeFrame.setBorder(BorderFactory.createLineBorder(settingsFrame.getBackground()));
    hiddenTimeFrame.setBackground(settingsFrame.getBackground());
    hiddenTimeFrame.setEditable(false);
    settingsFrame.add(hiddenTimeFrame, gbc);

    gbc.gridx = 1;
    timeFrame = new JTextField("", 15);
    settingsFrame.add(timeFrame, gbc);

    gbc.gridx = 0;
    gbc.gridy = 2;
    startSlideShow = new JButton("Start Slideshow");
    startSlideShow.addActionListener(this);
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.gridwidth = 3;
    settingsFrame.add(startSlideShow, gbc);
    settingsFrame.setVisible(true);
}

public static void main(String[] args) {
    new Slideshow().openSettingsFrame();
}


@Override
public void actionPerformed(ActionEvent e) {
    if(e.getSource() == addRootFolder) {
        JFileChooser jfc = new JFileChooser("");
        jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnVal = jfc.showOpenDialog(addRootFolder);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
            File f = jfc.getSelectedFile();
            rootFolder.setText(f.getPath());
        }
    } else if(e.getSource() == startSlideShow) {
        if(!rootFolder.getText().equals("")) {
            if(!timeFrame.getText().equals("")) {
                try {
                    int time = Integer.parseInt(timeFrame.getText());
                    openImageWindow(time);
                } catch (NumberFormatException ex) {
                    ex.printStackTrace();
                }

            }
        } else {
            //TODO: prompt
        }
    }
}

@Override
public void run() {
    File file = new File(rootFolder.getText());
    List list = Arrays.asList(file.list());
    Random random = new Random();
    int i = random.nextInt(list.size());
    while(haveUsed.contains(list.get(i).toString()) || !list.get(i).toString().endsWith(".jpg") ||
            !list.get(i).toString().endsWith(".bmp") || !list.get(i).toString().endsWith(".png")) {
        i = random.nextInt(list.size());
    }
    imageIcon = new ImageIcon(list.get(i).toString());
    imageFrame.repaint();
    imageFrame.revalidate();
    haveUsed.add(list.get(i).toString());
}

public void openImageWindow(int delay) {
    imageFrame = new JFrame("Slideshow v1.0");
    imageFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    imageFrame.setLayout(new BorderLayout());
    imageFrame.setSize(400, 400);
    File file = new File(rootFolder.getText());
    List list = Arrays.asList(file.list());
    Random random = new Random();
    int i = random.nextInt(list.size());
    imageIcon = new ImageIcon(list.get(i).toString());
    haveUsed.add(list.get(i).toString());
    jLabel = new JLabel(imageIcon);
    jLabel.setSize(399, 399);
    imageFrame.add(jLabel);
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    scheduledExecutorService.scheduleWithFixedDelay(this, delay, delay, TimeUnit.SECONDS);
    imageFrame.setVisible(true);
}

【问题讨论】:

  • 不要使用 ExecutorService,而是使用 Swing Timer,因为当您想要更新 UI 时使用它是安全的
  • @MadProgrammer 我已经接受了你的建议,但这并不能解决我的问题。但是感谢您的提示!
  • 我认为这不是“最佳”解决方案,只是对其他潜在问题的补救
  • @MadProgrammer 抱歉,是的,我刚刚学会了评论和回答之间的区别。
  • 别担心,当我第一次开始分析代码时,我的 cmets 往往是短而敏锐的,在我诊断和调试代码时寻找真正明显的东西 ;)

标签: java image swing


【解决方案1】:

所以,主要问题在于您的while-loop 选择下一张图片...

while(haveUsed.contains(list.get(i).toString()) || !list.get(i).toString().endsWith(".jpg") ||
        !list.get(i).toString().endsWith(".bmp") || !list.get(i).toString().endsWith(".png")) {
    i = random.nextInt(list.size());
}

基本上,由于某种原因,这似乎永远不会产生false 结果(您可以花一些时间调试它以找出原因)。

更简单的解决方案是在开始之前生成文件的List,然后只需使用Collections.shuffle 随机化List 并删除第一个元素

类似...

public void showNextImage() {
    try {
        Collections.shuffle(imageFiles);

        File imageFile = imageFiles.remove(0);

        jLabel.setIcon(new ImageIcon(ImageIO.read(imageFile)));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

public void openImageWindow(int delay) {

    imageFiles = new ArrayList<>(Arrays.asList(new File(rootFolder.getText()).listFiles(new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.getName().toLowerCase().endsWith(".jpg")
                    || pathname.getName().toLowerCase().endsWith(".png")
                    || pathname.getName().toLowerCase().endsWith(".bmp")
                    || pathname.getName().toLowerCase().endsWith(".gif");
        }
    })));

    imageFrame = new JFrame("Slideshow v1.0");
    imageFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    imageFrame.setLayout(new BorderLayout());
    imageFrame.setSize(400, 400);
    File file = new File(rootFolder.getText());
    List list = Arrays.asList(file.list());
    Random random = new Random();
    int i = random.nextInt(list.size());
    imageIcon = new ImageIcon(list.get(i).toString());
    haveUsed.add(list.get(i).toString());
    jLabel = new JLabel(imageIcon);
    jLabel.setSize(399, 399);
    imageFrame.add(jLabel);
    Timer timer = new Timer(delay, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            showNextImage();
        }
    });
    imageFrame.setVisible(true);
    timer.setInitialDelay(0);
    timer.start();


}

我添加了一个名为 imageFilesArrayList,它是指定目录中所有图像的列表,并使用 Swing Timer 更新 UI。当你加载它时,你应该确保将图像实际应用到JLabeljLabel.setIcon(new ImageIcon(ImageIO.read(imageFile)));

我个人发现ImageIO 是一种更好的读取/写入图像的方法,除了支持更多图像格式外,它还会在文件无法读取时抛出IOException,有助于诊断任何潜在问题

如果您想要目录的“实时”视图,那么我会使用您的 haveUsed List 并从 File 列表中删除元素

也许是……

List<File> imageFiles = new ArrayList<>(Arrays.asList(new File(rootFolder.getText()).listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.getName().toLowerCase().endsWith(".jpg")
                || pathname.getName().toLowerCase().endsWith(".png")
                || pathname.getName().toLowerCase().endsWith(".bmp")
                || pathname.getName().toLowerCase().endsWith(".gif");
    }
})));
imageFiles.removeAll(haveUsed);
Collections.shuffle(imageFiles);

File imageFile = imageFiles.remove(0);
haveUsed(imageFile);

jLabel.setIcon(new ImageIcon(ImageIO.read(imageFile)));

您需要将 haveUsedArrayList&lt;String&gt; 更改为 ArrayList&lt;File&gt;

【讨论】:

  • 谢谢你,你通过了解决方案:P 唯一的问题是图像是巨大的。 Windows 照片查看器会缩小它们吗?这是否也会因为某种原因使图像颠倒?我无法想象为什么会这样,但我也无法想象我为什么要拍一堆颠倒的照片。
  • 有些图片有一个“orientation”属性,它会影响照片的渲染方向。不幸的是,Java 并不直接支持这一点。是的,我认为 Windows 照片查看器确实对图像应用了一些缩放。您可以查看thisthis 了解有关缩放的一些想法
  • 您也可以查看this 了解有关方向的更多详细信息
【解决方案2】:

问题出在这条线:

imageIcon = new ImageIcon(list.get(i).toString());

您不会更改旧图像,而只是更新您的参考。您需要将其替换为:

imageIcon.setImage(ImageIO.read(new File(list.get(i).toString())));

【讨论】:

  • 虽然这肯定是个问题,但在我有限的测试中,代码从来没有那么远
  • @MadProgrammer 同意,刚注意到while循环,不停循环循环
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多