java - 动态更新时 JPanel 出现不需要的重画

标签 java swing jpanel bufferedimage javax.swing.timer

我有一个窗口,可以使用 javax.swing.Timer 动态更新 JPanel 上设置的缓冲图像

一切都按预期工作,但每次我调用动态更新时,似乎都会在当前更新的图像下方显示另一个缓冲图像。

下面给出了单击训练按钮(触发动态更新)之前和之后的窗口图像。

enter image description here

因为动态更新图像下方的图像看起来像初始屏幕。我重新检查了以下内容

  1. 是否将两个动态晶格对象添加到同一面板
  2. 多次调用 repaint()
  3. 动态晶格不需要的初始化

我在我的代码中找不到任何这些。我无法发布代码,因为它很大,并且每当我创建一个最小集来重现相同的行为时,它就不在那里。所以我确信我在项目代码中遗漏了某些内容或执行了某些操作,从而触发了此行为。关于如何调试这个或者为什么它要做这样的事情有什么建议吗?

谢谢

编辑

SSCCE 如下。如果执行,请单击“加载”按钮,然后单击“训练”按钮以获取错误。

(MapScreen.java - Main Class)
package test;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import test.DisplayLattice;
import test.SelfOrganizingMap;

public class MapScreen extends JFrame {

private double NUM_ITERATIONS = 0.0;
private double ETA = 0.0;
private double SPREAD_FACTOR = 0.0;
private double RADIUS = 0.0;
private int WIDTH = 0;
private int HEIGHT = 0;
private SelfOrganizingMap SOM = null;
private Timer REFRESH_TIMER = null; 
private JPanel pnlMap;
private JButton btnLoadParameters;
private JButton btnTrain;
private DisplayLattice displayScreen;


public MapScreen(double iterations, double learningRate, double spreadFactor, double radius, int option, int width, int height, int mapOption) {

    NUM_ITERATIONS = iterations;
    ETA = learningRate;
    SPREAD_FACTOR = spreadFactor;
    RADIUS = radius;
    WIDTH = width;
    HEIGHT = height;

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

    displayScreen = new DisplayLattice();
    pnlMap = displayScreen;
    pnlMap.setBounds(6, 130, 600, 600);
    getContentPane().add(pnlMap);


    btnLoadParameters = new JButton("Load Parameters");
    btnLoadParameters.setFont(new Font("Tahoma", Font.PLAIN, 11));
    btnLoadParameters.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0)
        {
            SOM = new SelfOrganizingMap(10000,0,0,13,displayScreen);
        }
    });
    btnLoadParameters.setBounds(192, 46, 126, 23);
    getContentPane().add(btnLoadParameters);

    btnTrain = new JButton("Train");
    btnTrain.setFont(new Font("Tahoma", Font.PLAIN, 11));
    btnTrain.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            initialObjectSetUp();
        }
    });
    btnTrain.setBounds(192, 72, 62, 23);
    getContentPane().add(btnTrain); 
}

private void initialObjectSetUp()
{
    SOM.initTrainSOM(null, 100, 0.25);
    REFRESH_TIMER = new Timer(100, SOM);
    REFRESH_TIMER.start();
}


public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            MapScreen frame = new MapScreen(100,0.25,0.0,0.0,1,100,0,0);
            frame.setVisible(true);
        }
    });

}   
}

(SelfOrganizingMap.java)
package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SelfOrganizingMap implements ActionListener {

private Node[][] SOM = null;
private double[][] NORM_MAP = null; //holds the L2 norm of each vector in the SOM[][].
@SuppressWarnings("unused")
private int GRID_OPTION = 0;
private int INPUT_DIMENSION = 0;
private int NUMER_OF_ITERATIONS = 0;
private int CURRENT_ITERATION=0;
private int SOM_HORIZONTAL_LENGTH = 0;
private int SOM_VERTICAL_LENGTH = 0;
private double INITIAL_LEARNING_RATE = 0.0;
private double LEARNING_RATE = 0.0;
private double MAX_RADIUS = 0.0; //radius at first epoch (t = 0)
private double RADIUS = 0.0;
private double TIME_STEP = 0.0; //lambda of X(t) = t0 * exp(-t/lambda)
private String INPUT_SAMPLES = null;
private DisplayLattice DISPLAY_SCREEN = null;


public SelfOrganizingMap(int numberOfNodes, int depth, int grid, int inputDimensison, DisplayLattice screen)
{
    INPUT_DIMENSION = inputDimensison;

    if(grid == 0)
    {
        int side = (int)Math.sqrt(numberOfNodes);
        SOM = new Node[side][side];
        NORM_MAP = new double[side][side];
        GRID_OPTION = grid;
        MAX_RADIUS = side/2;
        DISPLAY_SCREEN = screen;
    }


    RADIUS = MAX_RADIUS;
}

public void initTrainSOM(String input, int iterations, double learningRate)
{

    NUMER_OF_ITERATIONS = iterations;
    INITIAL_LEARNING_RATE = learningRate;
    LEARNING_RATE = INITIAL_LEARNING_RATE;
    TIME_STEP = NUMER_OF_ITERATIONS/Math.log(MAX_RADIUS);
    INPUT_SAMPLES = input;

}

private void singleCompleteRun()
{
    DISPLAY_SCREEN.render();
    System.out.println(CURRENT_ITERATION);
}

@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    if(CURRENT_ITERATION <= NUMER_OF_ITERATIONS)
    {
        singleCompleteRun();    
        CURRENT_ITERATION++;
    }

}

}

(DisplayLattice.java)
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class DisplayLattice extends JPanel  {

private BufferedImage img = new BufferedImage(500, 500, 1); 

public void paintComponent(Graphics g) {
    if (img == null)
        super.paintComponents(g);
    else
        g.drawImage(img, 0, 0, this);
}


public void render() {

float cellWidth = 100;
float cellHeight = 100;

    int imgW = img.getWidth();
    int imgH = img.getHeight();
    float r, g, b;
    Graphics2D g2 = img.createGraphics();
    g2.setBackground(Color.black);
    g2.clearRect(0,0,imgW,imgH);
    for (int x=0; x<100; x++) {
        for (int y=0; y<100; y++) {
            r = (float)Math.random();
            g = (float)Math.random();
            b = (float)Math.random();
            g2.setColor(new Color(r,g,b));
            g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
                        (int)cellWidth+1, (int)cellHeight+1);
        }
    }
    g2.setColor(Color.black);
    g2.dispose();
    repaint();
}

public BufferedImage getImage() {
    if (img == null)
        img = (BufferedImage)createImage(500, 500);

    return img;
}

public void setImage(BufferedImage bimg) {
    img = bimg;
}
}
(Node.java - Structure class for the SOM)
package test;
public class Node {

private int DIMENSION = 0;  
private int POSITION_X = 0;
private int POSITION_Y = 0; 
private double ACTIVATION_VALUE = 0.0; 

public Node(int Dimensions, int x, int y)
{
    DIMENSION = Dimensions; 
    setWeightVector();
    POSITION_X = x;
    POSITION_Y = y;
}

public int getX() {
    return POSITION_X;
}

public int getY() {
    return POSITION_Y;
}

public double getACTIVATION_VALUE() {
    return ACTIVATION_VALUE;
}

public void setPOSITION_X(int x) {
    POSITION_X = x;
}

public void setPOSITION_Y(int y) {
    POSITION_Y = y;
}

public void setACTIVATION_VALUE(double y) {
    ACTIVATION_VALUE= y;
}

private void setWeightVector()
{
    double temp[] = new double[DIMENSION];

    for(int i = 0; i<temp.length ; i++)
    {
        temp[i] =  Math.random();
    }

}

}

最佳答案

问题出在您的 DiaplyLattice 类上。

您覆盖了paintComponent,但调用了super.paintComponents(g)。请注意 paintComponents 末尾的额外 s!这当然是不需要的,应该是 super.paintComponent(g);

我希望你的方法如下:

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (img != null) {
        g.drawImage(img, 0, 0, this);
    }
}

现在,作为一个好的建议/提示,不要使用 null 布局,而是使用 LayoutManager 布局,并可能使用多层嵌套。它总是更容易。

此外,您还错过了 SSCCE 中的一个重要内容:SHORT 部分。这意味着您应该删除任何不必要的内容并复制/粘贴一个文件。

关于java - 动态更新时 JPanel 出现不需要的重画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17261618/

相关文章:

java - 打包 Java 应用程序时,属性文件未包含在 jar 文件中

java - 为什么 pom.xml 的 modelVersion 是必需的并且始终设置为 4.0.0?

Java Swing : Separation of logic and GUI

java - 如果您将当前对象的 Graphics2D 传递给另一个对象,它会在当前对象上绘制吗?

java - 在 JFrame 中引用 JPanel 的坐标

java - 从java中的gradle.properties访问属性?

java - 为什么 Properties.list(PrintWriter out) 不打印任何内容?

java - 如何隐藏或关闭弹出菜单 JDateChooser?

java - 为什么这个GridBagLayout没有按计划出现?

java - JLayeredPane 中的顶层未显示