【问题标题】:Updating an image contained in a JLabel - problems更新 JLabel 中包含的图像 - 问题
【发布时间】:2012-04-07 04:04:19
【问题描述】:

我目前在开始工作时遇到问题的应用程序部分是能够滚动并显示图像列表,一次一个。我从用户那里得到一个目录,通过该目录中的所有文件进行后台处理,然后加载一个仅包含 jpeg 和 png 的数组。接下来,我想用第一张图像更新 JLabel,并提供上一个和下一个按钮来滚动并依次显示每个图像。当我尝试显示第二张图片时,它没有得到更新......这是我到目前为止所得到的:

public class CreateGallery
{
    private JLabel swingImage;

我用来更新图像的方法:

protected void updateImage(String name) 
{
    BufferedImage image = null;
    Image scaledImage = null;
    JLabel tempImage;

    try
    {
        image = ImageIO.read(new File(name));
    } catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    // getScaledImage returns an Image that's been resized proportionally to my thumbnail constraints
    scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
    tempImage = new JLabel(new ImageIcon(scaledImage));
    swingImage = tempImage;
}

然后在我的 createAndShowGUI 方法中将 swingImage 放在...

private void createAndShowGUI() 
{
    //Create and set up the window.
    final JFrame frame = new JFrame();

    // Miscellaneous code in here - removed for brevity

    //  Create the Image Thumbnail swingImage and start up with a default image
    swingImage = new JLabel();
    String rootPath = new java.io.File("").getAbsolutePath();
    updateImage(rootPath + "/images/default.jpg");

    // Miscellaneous code in here - removed for brevity

    rightPane.add(swingImage, BorderLayout.PAGE_START);
    frame.add(rightPane, BorderLayout.LINE_END);
public static void main(String[] args) 
{
    SwingUtilities.invokeLater(new Runnable() 
    {
        public void run() 
        {
            UIManager.put("swing.boldMetal", Boolean.FALSE);
            new CreateGalleryXML().createAndShowGUI();
        }
    });
}

如果你已经走到这一步,第一张图片是我的 default.jpg,一旦我获得目录并识别该目录中的第一张图片,当我尝试更新 swingImage 时它就会失败。现在,我尝试使用 swingImage.setVisible() 和 swingImage.revalidate() 来强制它重新加载。我猜这是我的 tempImage = new JLabel 的根本原因。但我不确定如何将我的 BufferedImage 或 Image 转换为 JLabel 以便更新 swingImage。

【问题讨论】:

  • 我添加了一些信息,说明为什么您的 setVisible()/revalidate() 呼叫在这种情况下无法正常工作。希望这会让整个事情更清楚一点,至于为什么你会出现这种意外行为:-)
  • 我之前尝试过不同的 setVisible(false) 组合,而不是在 swingImage = tempImage; 之后将其设置回 true;并且还尝试在 setVisible(true) 之前和之后使用 .revalidate()。但我开始相信是新的 JLabel(new ImageIcon(scaledImage) 导致了问题......仍在寻找它并试图弄清楚......

标签: java image swing jlabel


【解决方案1】:

无需为每个Image 创建JLabelNew Instance,只需使用JLabelJLabel#setIcon(...) 方法来更改图像。

一个小示例程序:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SlideShow extends JPanel
{
    private int i = 0;
    private Timer timer;
    private JLabel images = new JLabel();
    private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
                            UIManager.getIcon("OptionPane.errorIcon"),
                            UIManager.getIcon("OptionPane.warningIcon")};
    private ImageIcon pictures1, pictures2, pictures3, pictures4;
    private ActionListener action = new ActionListener()
    {
        public void actionPerformed(ActionEvent ae)
        {                       
            i++;
            System.out.println(i);

            if(i == 1)
            {
                pictures1 = new ImageIcon("image/caIcon.png");
                images.setIcon(icons[i - 1]);
                System.out.println("picture 1 should be displayed here");
            }
            if(i == 2)
            {
                pictures2 = new ImageIcon("image/Keyboard.png");
                images.setIcon(icons[i - 1]);   
                System.out.println("picture 2 should be displayed here");
            }
            if(i == 3)
            {
                pictures3 = new ImageIcon("image/ukIcon.png");
                images.setIcon(icons[i - 1]);
                System.out.println("picture 3 should be displayed here");  
            }
            if(i == 4)
            {
                pictures4 = new ImageIcon("image/Mouse.png");
                images.setIcon(icons[0]);   
                System.out.println("picture 4 should be displayed here");  
            }
            if(i == 5)
            {
                timer.stop();
                System.exit(0);
            }
            revalidate();
            repaint();
        }
    };

    public SlideShow()
    {
        JFrame frame = new JFrame("SLIDE SHOW");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);

        frame.getContentPane().add(this);

        add(images);

        frame.setSize(300, 300);
        frame.setVisible(true); 
        timer = new Timer(2000, action);    
        timer.start();  
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new SlideShow();
            }
        });
    }
}

既然你是用 ImageIO 做的,这里有一个与 JLabel using ImageIO 相关的好例子

与您的案件有关的信息,关于正在发生的事情:

在您的createAndShowGUI() 方法中,您初始化了您的JLabel (swingImage),然后您将其添加到了您的JPanel,从而间接添加到了JFrame

但是现在在您的updateImage() 方法中,您正在初始化一个新的JLabel,现在它通过写入tempImage = new JLabel(new ImageIcon(scaledImage)); 驻留在另一个内存位置,然后您将您的swingImage(JLabel) 指向这个新创建的JLabel,但这个新创建的JLabel 从未添加到JPanel,在任何时候。因此,即使您尝试revalidate()/repaint()/setVisible(...),它也将不可见。因此,要么将 updateImage(...) 方法的代码更改为:

protected void updateImage(String name) 
{
    BufferedImage image = null;
    Image scaledImage = null;
    JLabel tempImage;

    try
    {
        image = ImageIO.read(new File(name));
    } 
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    // getScaledImage returns an Image that's been resized 
    // proportionally to my thumbnail constraints
    scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
    tempImage = new JLabel(new ImageIcon(scaledImage));
    rightPane.remove(swingImage);
    swingImage = tempImage;
    rightPane.add(swingImage, BorderLayout.PAGE_START);
    rightPane.revalidate();
    rightPane.repaint(); // required sometimes
}

或者使用前面提到的JLabel.setIcon(...) :-)

更新答案

这里看看New JLabel是怎么放在旧的位置的,

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SlideShow extends JPanel
{
    private int i = 0;
    private Timer timer;
    private JLabel images = new JLabel();
    private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
                            UIManager.getIcon("OptionPane.errorIcon"),
                            UIManager.getIcon("OptionPane.warningIcon")};
    private ActionListener action = new ActionListener()
    {
        public void actionPerformed(ActionEvent ae)
        {                       
            i++;
            System.out.println(i);          

            if(i == 4)
            {
                timer.stop();
                System.exit(0);
            }
            remove(images);
            JLabel temp = new JLabel(icons[i - 1]);
            images = temp;
            add(images);
            revalidate();
            repaint();
        }
    };

    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("SLIDE SHOW");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);    

        this.setLayout(new FlowLayout(FlowLayout.LEFT));    

        add(images);

        frame.getContentPane().add(this, BorderLayout.CENTER);

        frame.setSize(300, 300);
        frame.setVisible(true); 
        timer = new Timer(2000, action);    
        timer.start();  
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new SlideShow().createAndDisplayGUI();
            }
        });
    }
}

对于您的问题:在我尝试过的两个选项中,一个比另一个更好吗?

setIcon(...) 相对于其他方式具有优势,从某种意义上说,在添加/删除 JLabel 之后,您不必担心 revalidate()/repaint() 事情。此外,您不需要每次都记住JLabel 的位置,添加它。它保持在它的位置,你只需调用一个方法来改变图像,没有附加任何条件,工作就完成了,没有任何头疼的问题。

对于问题 2:我有点怀疑,Array of Records 是什么?

【讨论】:

  • 好方法;有一个例子here
  • 谢谢你 :-),你确实有每个情况的例子,今天毫无疑问,呵呵 :-)
  • 谢谢好牛!您的 swingImage.setIcon(icon) 解决方案有效......我想看看您改进后的 updateImage 方法,看看它是如何工作的,还看看@trashgod 的链接。再一次,你们两个都帮了我!
  • @nIcE cOw not 我有无穷无尽的财富,there are top 10,在我们努力帮助另一个人时帮助我....
  • 是的,没错,如果您发现给定的答案符合您的期望,那么您可以将其标记为正确,如here 解释的那样,或者如果所谓的答案来自您身边,然后您可以发布自己的答案并将其标记为正确,这两种方式都将关闭当前线程,并帮助未来的访问者从中获得帮助:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多