Question

I have a window that dynamically updates the buffered image set on a JPanel using javax.swing.Timer

Everything works as expected but every time I invoke the dynamic update there seems to be another buffered image displayed below the currently updating one.

The image of the window before and after clicking the train button (which triggers the dynamic update) is given below.

enter image description here

Since the image below the dynamically updating image looks like the initial screen. I rechecked the following

  1. Whether I'm adding two dynamic lattice objects to the same panel
  2. Multiple calls of repaint()
  3. Unwanted initialization of the dynamic lattice

I could not find any of these in my code. I cannot post the code since it is huge and whenever I'm creating a minimal set to reproduce the same behavior it is not there. So I'm sure I'm missing something or doing something on my project code which triggers this behavior. Any suggestions on how to debug this or why it is doing something like this?

Thank you

EDIT

SSCCE is give below. If executing, click the load button followed by the train button to get the error.

(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();
    }

}

}
Was it helpful?

Solution

The problem is your DiaplyLattice class.

You overrode paintComponent but you invoke super.paintComponents(g). Notice the extra s you have at the end of paintComponents! This of course is unwanted and should be super.paintComponent(g);

I would have you method as follow:

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

Now, just as a good advice/tip to give, don't use null layout and rather use LayoutManager's and possibly use several level of nesting. It's always easier.

Also, you missed an important thing in SSCCE: the SHORT part. Meaning that you should remove anything unnecessary and have a single file to copy/paste.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top