Reputation: 117
Why won't my image repaint for a simple animation? I call repaint() from two different methods and one causes repaint but the other doesn't. The method that does force the repaint is generated from an event listener. The one that doesn't is a timed animation thread. I know the animation thread is running correctly, and as long as I continuously slide the slider, it displays perfectly. Help please!
PS yes, I've seen many similar problems here, and I've tried validate, revalidate, and using paint vs paintComponent. Four classes that comprise the code follow:
import javax.swing.*;
public class gutz{
public static int windowWidth = 640;
public static int windowHeight = 480;
public static void main(String[] args){
hBod hb1 = new hBod(50, 30, 21, 111, 7, -11); //mass, radius, xpos, ypos, xvel, yvel
Thread t1 = new Thread(hb1);
windowmakr w = new windowmakr();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.setSize(windowWidth, windowHeight);
w.setVisible(true);
t1.start();
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class windowmakr extends JFrame {
private JSlider slider;
private drawr panel;
public windowmakr(){
super("Orbit Explorer");
panel = new drawr();
panel.setBackground(Color.BLACK);
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
slider.setMajorTickSpacing(10);
slider.setPaintTicks(true);
slider.addChangeListener(
new ChangeListener(){
public void stateChanged(ChangeEvent e){
panel.setSpeed(slider.getValue());
}
}
);
add(slider, BorderLayout.SOUTH);
add(panel, BorderLayout.CENTER);
}
}
import java.awt.*;
import javax.swing.*;
public class drawr extends JPanel{
private int diameter = 10;
private static int rad;
private static int xpos;
private static int ypos;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillOval((gutz.windowWidth-diameter)/2, ((gutz.windowHeight-diameter)/2)-40, diameter, diameter);
g.setColor(Color.CYAN);
g.fillOval(xpos, ypos, rad, rad);
}
/* public void paint(Graphics g){
super.paint(g);
g.setColor(Color.ORANGE);
g.fillOval((gutz.windowWidth-diameter)/2, ((gutz.windowHeight-diameter)/2)-40, diameter, diameter);
g.setColor(Color.CYAN);
g.fillOval(xpos, ypos, rad, rad);
}
*/
public void setSpeed(int newD){
diameter = (newD >= 0 ? newD : 10);
repaint();
}
public void renderImage(int r, int xp, int yp){
rad=r;
xpos=xp;
ypos=yp;
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPreferredSize();
}
}
public class hBod implements Runnable{
private int mass;
private int rad;
private int xpos;
private int ypos;
private double xvel;
private double yvel;
public drawr render;
public hBod(int m, int r, int xp, int yp, double xv, double yv){
mass=m;
rad=r;
xpos=xp;
ypos=yp;
xvel=xv;
yvel=yv;
render = new drawr();
}
public void run(){
try{
while(true){
xpos+=xvel;
ypos+=yvel;
yvel+=1;
System.out.printf("rad - %d, xpos - %d, ypos - %d\n", rad, xpos, ypos);
render.renderImage(rad, xpos, ypos);
Thread.sleep(1000);
}
}catch(Exception e){}
}
}
Upvotes: 4
Views: 20533
Reputation: 1002
You can use the getContentPane().repaint() method in your JFrame class
Upvotes: 6
Reputation: 24616
Like I said before, the problem lies in this line render = new drawr();
inside the hBod
constructor. Create a single instance like private drawr panel = new drawr()
inside the gutz
class and pass it to other two classes using their constructor, like hBod hb1 = new hBod(50, 30, 21, 111, 7, -11, panel)
and windowmakr w = new windowmakr(panel)
and simply use this reference to point to panel.renderImage(...)
inside hBod
class and panel.setSpeed(...)
from windowmakr
class.
Here is the modified code, Please learn Java Coding Conventions :
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class Gutz {
public static int windowWidth = 640;
public static int windowHeight = 480;
public static void main(String[] args){
Drawr panel = new Drawr();
panel.setBackground(Color.BLACK);
HBod hb1 = new HBod(50, 30, 21, 111, 7, -11, panel); //mass, radius, xpos, ypos, xvel, yvel
Thread t1 = new Thread(hb1);
WindowMakr w = new WindowMakr(panel);
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.setSize(windowWidth, windowHeight);
w.setVisible(true);
t1.start();
}
}
class WindowMakr extends JFrame {
private JSlider slider;
private Drawr panel;
public WindowMakr(Drawr p){
super("Orbit Explorer");
final Drawr panel = p;
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
slider.setMajorTickSpacing(10);
slider.setPaintTicks(true);
slider.addChangeListener(
new ChangeListener(){
public void stateChanged(ChangeEvent e){
panel.setSpeed(slider.getValue());
}
}
);
add(slider, BorderLayout.SOUTH);
add(panel, BorderLayout.CENTER);
}
}
class Drawr extends JPanel{
private int diameter = 10;
private static int rad;
private static int xpos;
private static int ypos;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillOval((Gutz.windowWidth-diameter)/2, ((Gutz.windowHeight-diameter)/2)-40, diameter, diameter);
g.setColor(Color.CYAN);
g.fillOval(xpos, ypos, rad, rad);
}
public void setSpeed(int newD){
diameter = (newD >= 0 ? newD : 10);
repaint();
}
public void renderImage(int r, int xp, int yp){
rad=r;
xpos=xp;
ypos=yp;
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPreferredSize();
}
}
class HBod implements Runnable{
private int mass;
private int rad;
private int xpos;
private int ypos;
private double xvel;
private double yvel;
public Drawr render;
public HBod(int m, int r, int xp, int yp, double xv, double yv, Drawr panel){
mass=m;
rad=r;
xpos=xp;
ypos=yp;
xvel=xv;
yvel=yv;
render = panel;
}
public void run(){
try{
while(true){
xpos+=xvel;
ypos+=yvel;
yvel+=1;
System.out.printf("rad - %d, xpos - %d, ypos - %d\n", rad, xpos, ypos);
render.renderImage(rad, xpos, ypos);
Thread.sleep(1000);
}
}catch(Exception e){}
}
}
Upvotes: 3