Java GUI : Image will be overwritten, 路径相同 -> 在框架中显示它(图像仍然相同)

标签 java image swing user-interface filepath

我想在我的相框上显示变化的图像。图像路径始终相同,但图像每 10 秒就会被另一个程序覆盖。 问题是,当我用另一个同名图像覆盖它时,图像没有改变。所以在我的理解中:编译器查看路径中的每一个外观并获取图像 -> 当图像更改时,它将在框架上更改!

我希望您理解我的问题并且有人可以帮助我。

    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.io.File; 

    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;

    public class GUI extends JFrame{

        public ImageIcon imageBar;

        public JLabel labelimage1;
        private JLabel labelimage2;

        private JLabel bar1 = new JLabel();
        private JLabel bar2 = new JLabel();
        private JLabel bar3 = new JLabel();
        private JLabel bar4 = new JLabel();
        private JLabel bar5 = new JLabel();

        private JButton buttonBar1 = new JButton("1");
        private JButton buttonBar2 = new JButton("2");
        private JButton buttonBar3 = new JButton("3");
        private JButton buttonBar4 = new JButton("4");
        private JButton buttonBar5 = new JButton("5");

        private JPanel panel1 = new JPanel();
        private JPanel panel2 = new JPanel();
        private JPanel panel3 = new JPanel();

        private JFrame window = new JFrame("Interface");

        public GUI(){

            //set the layouts
            panel1.setLayout(new GridLayout(1, 2)); 
            panel2.setLayout(new GridLayout(2, 1));
            panel3.setLayout(new GridLayout(2, 5));

            //place Panel2 and Panel3 in the window
            panel1.add(panel2); 
            panel1.add(panel3);

            //----Panel2
            //refreshImage();


            //----Panel3        
            panel3.add(buttonBar1); //add the bars 1-5 on panel3
            panel3.add(buttonBar2);
            panel3.add(buttonBar3);
            panel3.add(buttonBar4);
            panel3.add(buttonBar5);

            //configure the frame
            window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            window.setVisible(true);
            window.setSize(800, 400);
            window.getContentPane().add(panel1);
        }


        public void refreshImage() {

            panel2.removeAll(); //delete the old panel
            //panel2.repaint();
            //panel2.revalidate()

            DrawImage pan = new DrawImage();

            panel2.add(pan);
            panel2.add(labelimage2);
        }
}


import javax.swing.ImageIcon;
import javax.swing.JPanel;


public class DrawImage extends JPanel implements ActionListener{

    private ImageIcon image;

    public DrawImage(){
        image = new ImageIcon("C:\\Users\\usuario\\Desktop\\image.png");
    }

    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        image.paintIcon(this, g, 50, 50);
        repaint();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }

}

import java.io.File;

public class Main {

    public static void main(String[] args) {

        GUI Interface = new GUI(); 

        while(true)
        {
            Interface.refreshImage(); 
            try {
                        Thread.sleep(5000); //wait for 5000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
        }

    }

}

非常感谢!

最佳答案

可能的原因是 Java 将与源名称关联的图像缓存在内存中。因此,Java 只是返回缓存的版本,而不是尝试再次重新加载图像。

您可以使用ImageIcon#getImage#flush强制Java重建图像

问题

  • 您正在从事件调度线程以外的线程调用refreshImage,这可能会导致组件更新出现问题并导致渲染伪影
  • 您正在强制删除 DrawImage Pane 并添加新实例,而不是尝试重新加载图像
  • 您正在 paintComponent 方法中调用 repaint,请勿执行此操作...

您应该考虑使用 Swing Timer ,这将允许您安排定期更新并在事件调度线程的上下文中收到通知。

您可以提供一个简单的refresh方法来刷新当前的ImageIcon并安排面板的重新绘制...或者您可以只使用JLabel 节省自己的时间

Image#flush的示例

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SlideShow {

    public ImageIcon imageBar;

    public static void main(String[] args) {
        new SlideShow();
    }

    public SlideShow() {
        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 DrawImage());

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class DrawImage extends JPanel {

        private ImageIcon image;

        public DrawImage() {
            image = new ImageIcon("D:\\thumbs\\image.png");
            Timer timer = new Timer(5000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    refresh();
                }
            });
            timer.start();
        }

        public void refresh() {
            image.getImage().flush();
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image.getImage(), 0, 0, this);
        }

    }
}

这样做的问题是,因为图像数据是在后台线程中加载的,所以当组件第一次重新绘制时,它可能不可用,这可能会使组件出现闪烁。

更好的方法是使用 ImageIO.read,这将确保在方法返回之前完全加载图像,这里的缺点是可能会导致应用程序暂时“暂停”当图像加载时,就我个人而言,我会使用刷新方法来停止计时器(或将计时器设置为不重复) ),启动一个后台Thread来加载图像(使用ImageIO.read)调用repaint(这是线程安全的)并重新启动计时器...

关于Java GUI : Image will be overwritten, 路径相同 -> 在框架中显示它(图像仍然相同),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23706492/

相关文章:

html - 我可以用 CSS 替换图像标签的图像吗?

java - 如何将 Mongodb 与 Android 应用程序连接

java - 如何使用 Guice 重新初始化 Controller 中的注入(inject)组件?

java - 如何将当前用户的用户名与特定参数进行比较?

java - 取消匿名SwingWorker

java - 在 JComboBox 上添加 ListSelectionListener

java - Swing 上自定义组件的问题

java - 将值从适配器传递到导航组件中的 BottomNavigationView fragment

image - k-最近邻 VS 相似性搜索

c++ - 在 Allegro 中创建光标?