Synex
Synex

Reputation: 213

Having trouble with dynamically updating a BufferedImage

I'm trying to render a dynamically changing image on a JPanel. I have tried many things and I simply do not get how to do it or what I'm doing wrong and I'm at the point of going insane. I'm new to swing and this is a small but essential part of my program which enables me to see what I'm doing.

The simple requirement is the picture rendered initially in the JPanel in the code mentioned below should update at each tick with random colors. I cannot get the image to update. Instead I get another square appearing in the middle of the image I'm trying to update and that small square dynamically changes. I do not know what I'm doing wrong. Please let me know how to rectify the code below so I could get the whole image to update.

Thank you.

The code is as follows

(MainTest.java)

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

public class MainTest extends JFrame {
static ImageEditor img ;
JPanel panel;
Timer to;

public MainTest()
{
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(265, 329);
    getContentPane().setLayout(null);
    img =  new ImageEditor();
    panel = new ImageEditor();
    panel.setBounds(10, 11, 152, 151);
    panel.add(img);
    getContentPane().add(panel);

    JButton btnIterate = new JButton("Iterate");
    btnIterate.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {


            ThirdClass t = new ThirdClass(img);
            to = new Timer(10,t);
            to.start();             
        }

    });
    btnIterate.setBounds(10, 230, 89, 23);
    getContentPane().add(btnIterate);

}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            MainTest frame = new MainTest();
            //frame.getContentPane().add(imgx);
            frame.setVisible(true);
        }
    });

}
}

(ImageEditor.java)
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

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

private static BufferedImage img = new BufferedImage(100, 100, 1);  
public ImageEditor() {
    render();
}

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


public void render() {

float cellWidth = 10;
float cellHeight = 10;

    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(100, 100);

    return img;
}

public void setImage(BufferedImage bimg) {
    img = bimg;
}
}


(ThirdClass.java)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class ThirdClass implements ActionListener {

static ImageEditor mock;

public ThirdClass(ImageEditor img)
{
    mock = img;
    Train();
}

public void Train()
{
    mock.render();
}

@Override
public void actionPerformed(ActionEvent arg0) {
    Train();
}

    }

Upvotes: 1

Views: 1434

Answers (2)

Synex
Synex

Reputation: 213

After my initial post of the above question I have gone back to the basics and managed to answer my own question.

I am inserting the complete code below so another user having the same problem would not have to go through the same process over again.

My mistake was very trivial. However for people starting swing I think this might be helpful

(MainTest.java)
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class MainTest extends JFrame { 

ImageEditor img;
JPanel panel;
Timer t;

public MainTest()
{
    setSize(600,600);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    getContentPane().setLayout(null);

    img = new ImageEditor();
    panel = img;
    panel.setBounds(0, 0, 510, 510);
    getContentPane().add(panel);

    JButton btnStart = new JButton("Start");
    btnStart.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            test();
        }
    });
    btnStart.setBounds(0, 528, 89, 23);
    getContentPane().add(btnStart);
}

private void test() {
    Train tx = new Train(img);
    t = new Timer(100, tx);
    t.start();
}

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

  }

}

(ImageEditor.java)
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

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

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

public ImageEditor() {
    setLayout(null);
}

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

public void render() {

float cellWidth = 10;
float cellHeight = 10;

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

}

(Train.java this class was named ThirdClass.java in my question)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Train implements ActionListener {

ImageEditor temp;

Train(ImageEditor img)
{
    temp = img;
}

public void train()
{
    temp.render();  
}

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

}

Thank you for all who commented and answered my question.

Upvotes: 0

AJMansfield
AJMansfield

Reputation: 4129

From the code:

img =  new ImageEditor();
panel = new ImageEditor();
panel.setBounds(10, 11, 152, 151);
panel.add(img);
getContentPane().add(panel);

You are defining img as an ImageEditor, but you probably meant for it to be a BufferedImage. You are then adding it to panel, which is another ImageEditor - but it is being added through the superclass method JPanel.add, when you probably meant to use the method you wrote, ImageEditor.setImage().

EDIT: To summarize:

The tiny block of updating pixels you described is the BufferedImage (img.img), inside of your ImageEditor img, which is in turn inside of the ImageEditor panel, which is itself inside the applet's content pane.

  • replace static ImageEditor img in the MainTest class with BufferedImage img

  • replace img = new ImageEditor in MainTest's no-args constructor with img = new BufferedImage()

  • replace panel.add(img) in MainTest's no-args constructor with panel.setImage(img)

  • replace static ImageEditor mock in the ThirdClass class with BufferedImage mock

  • replace the ImageEditor img argument in ThirdClass's constructor with BufferedImage img

  • replace any other stuff involving img to correctly handle it as a BufferedImage

One other thing, although this problem isn't itself the cause of any program malfunction, you should rename the Train() method in ThirdClass to something like train() so it matches proper java style.

Upvotes: 2

Related Questions