通过单击按钮循环浏览 Jlabel 的图像时的 for 循环问题

Posted

技术标签:

【中文标题】通过单击按钮循环浏览 Jlabel 的图像时的 for 循环问题【英文标题】:for loop issue when cycling through images for Jlabel with button click 【发布时间】:2016-07-28 16:01:20 【问题描述】:

在 java 应用程序中,我有一个 Jlabel,我想在每次单击按钮时为其分配一个新图像,使用 for 循环我可以让它只显示最后一个图像,在图像之间跳过所有图像,我知道那里是我的逻辑错误,也许我不应该使用 for 循环?任何建议

 private String imageList[];
 ImageIcon image;
 imageList =  new String[] "src\\Tour_Eiffel_Wikimedia_Commons.jpg","src\\Ben.jpg", "src\\Rio.jpg", "src\\Liberty.jpg", "src\\Pyramid.jpg";

 //constructor setting first image to display on load
public GeographyGameGUI() 
       image = new ImageIcon(imageList[0]);
            imageLbl.setIcon(image);
 

  //button method
   private void nextBtnActionPerformed(java.awt.event.ActionEvent evt)                                         


      for (imgCount = 1; imgCount < imageList.length; imgCount++) 
            image = new ImageIcon(imageList[imgCount]);
            imageLbl.setIcon(image);

    

如果我不使用 for 循环而只使用我在按钮方法之外声明的计数器(如下所示),它会正确循环显示图像,但会遇到 ArrayIndexOutOfBoundsException。这里的最佳做法是什么?谢谢

 image = new ImageIcon(imageList[imgCount]);
     imageLbl.setIcon(image);
    imgCount++;

【问题讨论】:

【参考方案1】:

本质上,您是在阻止事件调度线程,阻止它更新 UI。更多详情请见Concurrency in Swing

相反,您应该使用 javax.swing.Timer 来循环图像,让 UI 在切换到下一个之前更新...

更多详情请见How to use Swing Timers。

Java 数组是零索引的,这意味着数组中的第一个元素是位置0,而不是1

不要在代码中直接引用src,一旦构建和打包应用程序,src 目录将不存在

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test 

    public static void main(String[] args) 
        new Test();
    

    public Test() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                    ex.printStackTrace();
                

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class TestPane extends JPanel 

        private JLabel label;
        private String[] imageList = new String[] "/Tour_Eiffel_Wikimedia_Commons.jpg","/Ben.jpg", "/Rio.jpg", "/Liberty.jpg", "/Pyramid.jpg";

        public TestPane() 
            setLayout(new BorderLayout());
            label = new JLabel();
            add(label);

            JButton btn = new JButton("Play");
            btn.addActionListener(new ActionListener() 
                @Override
                public void actionPerformed(ActionEvent e) 
                    btn.setEnabled(false);
                    Timer timer = new Timer(1000, new ActionListener() 
                        private int count;
                        @Override
                        public void actionPerformed(ActionEvent e) 
                            if (count < imageList.length) 
                                try 
                                    label.setIcon(
                                            new ImageIcon(
                                                    ImageIO.read(
                                                            TestPane.this.getClass().getResource(imageList[count]))));
                                 catch (IOException exp) 
                                    exp.printStackTrace();
                                
                                count++;
                             else 
                                ((Timer)e.getSource()).stop();
                            
                        
                    );
                    timer.stop();
                
            );
        

        @Override
        public Dimension getPreferredSize() 
            return new Dimension(200, 200);
        

    


【讨论】:

【参考方案2】:

您的计数器到达数组的末尾,因此您超出了边界异常。每次递增后,您应检查是否已到达数组末尾,如果已到达,请将计数器设置为 0。

如果您想通过单击延迟迭代一些图像,您需要使用SwingWorker。在您的动作侦听器中使用延迟将暂停事件调度线程,这意味着没有其他更新或与摆动组件的交互可用(刷新也可能无法正确完成)。

如果您在很短的时间内进行了几次更新 (setIcon),Swing 通常会在最后一个更新之后刷新组件,这意味着只有最后一个图像可见。

看看这里:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

【讨论】:

以上是关于通过单击按钮循环浏览 Jlabel 的图像时的 for 循环问题的主要内容,如果未能解决你的问题,请参考以下文章

type=file 浏览上传时的文件类型可以自己定义?

通过 ICommands 删除按钮单击时的 ListBoxItem

通过打字稿更改按钮单击时的svg颜色

如何在每个 Qlabel PyQt5 中显示两个图像

使用“单击”功能循环数组

C# 中的循环按钮背景图像