【问题标题】:How to display evolving BufferedImage on a JPanel如何在 JPanel 上显示不断变化的 BufferedImage
【发布时间】:2013-04-22 03:09:46
【问题描述】:

我需要在 JPanel 上显示不断变化的 BufferedImages。代码结构如下格式,我编译了一个SSCCE如下。

以下类在 Eclipse 中的 SSCCE1 项目中

类 DisplayLattice.Java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;   
import javax.swing.JPanel;

public class DisplayLattice extends JPanel {

    private BufferedImage IMAGE = null;
    private BufferedImage DISPLAY_IMAGE = null;

    public DisplayLattice()
    {
        IMAGE = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
        render();
    }

    public DisplayLattice(BufferedImage map) {
        IMAGE = map;
        render();
    }

    public void paint(Graphics g) {
        if (IMAGE == null)
            super.paint(g);
        else
            g.drawImage(IMAGE, 0, 0, this);
    }

    public void render() {

    int cellWidth = 5;
    int cellHeight = 5;

        int imgW = IMAGE.getWidth();
        int imgH = IMAGE.getHeight();
        DISPLAY_IMAGE = new BufferedImage(imgW*cellWidth, imgH*cellHeight, 1);          
        Graphics2D g2 = IMAGE.createGraphics();
        g2.clearRect(0,0,DISPLAY_IMAGE.getWidth(),DISPLAY_IMAGE.getHeight());

        for (int x=0; x<imgW; x++) {
            for (int y=0; y<imgH; y++) {
                g2.setColor(new Color(IMAGE.getRGB(x, y)));
                g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
                            (int)cellWidth, (int)cellHeight);
            }
        }
        g2.setColor(Color.black);
        g2.dispose();
        repaint();
        revalidate();
        System.out.println("XX");
    }   

    public void setImage(BufferedImage image)
    {
        IMAGE = image;
    }
}

类 SelfOrganizingMap.java

import java.awt.Color;
import java.awt.image.BufferedImage;

public class SelfOrganizingMap {

    public void methodTrain()
    {
        for(int i = 0; i < 100; i++)
        {
            new DisplayLattice(exportImageNorm());
        }

    }

    private BufferedImage exportImageNorm()
    {
        BufferedImage colorNodes = new BufferedImage(200, 200, 1);
        double[][] normL2values = new double[200][200];
        float t = 0.0f;
        for(int i = 0; i < normL2values.length ; i++){
            for(int j = 0; j < normL2values[0].length; j++){
                t = (float) Math.random();
                colorNodes.setRGB(i, j, (new Color(t,t,t)).getRGB());
            }
        }
        System.out.println("LL");
        return colorNodes;
    }

}

以下类在SSCCE2项目中

类 MapScreen.Java(主类)

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class MapScreen extends JFrame {
    private int WIDTH = 0;
    private int HEIGHT = 0;
    private DisplayLattice pnlMap;

    public MapScreen(int mapOption) {


        setType(Type.UTILITY);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("Map");
        setSize(600, 600);
        setLocation(150,150);
        getContentPane().setLayout(null);

        pnlMap = new DisplayLattice();
        pnlMap.setBounds(6, 130, 582, 440);
        getContentPane().add(pnlMap);

        JButton btnNewButton = new JButton("New button");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                new SelfOrganizingMap().methodTrain();
            }
        });
        btnNewButton.setBounds(10, 81, 89, 23);
        getContentPane().add(btnNewButton);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                MapScreen frame = new MapScreen(5);
                frame.setVisible(true);
            }
        });

    }
}

我想要实现的是,当我单击 MapScreen 类上的 JButton 时,我需要 JPanel,它是 SSCCE1 项目中 DisplayLattice 的一个实例,以动态更改 SelfOrganzingMap 类中 methodTrain() 中指定的迭代次数.

我目前遇到的问题是我在每次迭代时在 SelfOrganizingMap 类中设置的 bufferedImage 没有在显示的 JPanel 中设置。

如何解决这个问题?进行这种类型的可视化的最佳方法是什么,请记住,这里介绍的所有三个类都非常庞大,在实际应用程序中有很多方法。

【问题讨论】:

  • 当我深入了解时,您可能希望阅读 Performing Custom Painting,因为不推荐覆盖 paint ;)
  • 不明白你DisplayLattice类的意义。您调用 render() 方法并创建图像,但我看不到您在哪里使用图像。无需执行 revalidate()。当您从面板添加/删除组件时,您会重新验证。此外,您应该重写 getPreferredSize() 方法以返回图像的大小,以便可以将面板添加到另一个面板并以适当的大小显示。
  • @camicker 你能更具体一点吗?创建 DisplayLattice 的目的是放大传递给它的图像,以便我可以用矩形表示每个数组元素。 render 方法还有另一部分计算一些值。我没有包括它,因为那不是我的问题所在。对不起,如果我误导了你。

标签: java swing jpanel bufferedimage


【解决方案1】:

(您遇到的)主要问题在于您的 methodTrain 方法。

new DisplayLattice(exportImageNorm());

这只是创建DisplayLattice 的一个新实例,与实际显示在屏幕上的实例无关...

我能想到的最简单的解决方案是简单地将您在MapScreen 中创建的引用传递给methodTrain 方法...

new SelfOrganizingMap().methodTrain(pnlMap);

这将允许您执行类似...

public void methodTrain(DisplayLattice map) {
    for (int i = 0; i < 100; i++) {
        map.setImage(exportImageNorm());
    }
}

在此之后您唯一需要做的另一件事是在重新分配图像后在 setImage 方法中添加 repaint

挑剔

  • 不要用setBounds,用LayoutManager,认真的,努力吧,它会给你无尽的回报......
  • 不要覆盖paint,而是使用paintComponent。这是提供自定义绘画的推荐方法。此外,除非您绝对有具体的理由不这样做,否则您必须致电 super.paintXxx,如果不这样做,您最好知道会出现什么问题,以便解决问题。
  • repaint 之后无需调用revalidaterevalidate 将自行安排repaint
  • 你也可以看看Code Conventions for the Java Programming Language

【讨论】:

  • +1,我刚接触到methodTrain()方法,现在不用担心了。
  • @MadProgrammer,感谢您的快速回复。我现在可以在 JPanel 更新上获得一次图像。但上述修复仅在所有迭代完成后才显示图像。但我需要在每次迭代而不是在所有迭代结束时显示生成的图像。
  • 您希望它动画化还是希望输出窗格显示每个图像(如网格)?
  • @MadProgrammer 我希望显示每次迭代生成的图像。所以当图像替换为后续生成的图像时,它会形成一种动画。所以每次迭代生成的每张图像都应该更新到相同的面板空间。我不想要网格,所以我可以看到所有图像。点击播放按钮后,小程序中的输出应类似于 this
  • 您遇到的问题是您在事件调度线程的上下文中生成图像,该线程负责处理重绘请求等。因此,在actionPerformed 方法实际存在之前,不会发生重绘。您有两个选择,您可以使用 javax.swing.Timer 在每个“刻度”上生成一个新图像或使用 SwingWorker 并使用 publish/process 方法更新图像。更多详情请关注Concurrency in Swing
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-16
  • 1970-01-01
  • 2019-07-08
  • 2013-12-29
  • 2019-08-30
  • 2020-12-15
  • 1970-01-01
相关资源
最近更新 更多