repaint() not working in a Thread - java

i just started learning java 2 weeks ago so i don't really understand to much about java yet.I'm trying to make a ball bounce around or move around inside the frame. but it doesn't repaint/update when i run it in a Thread, but it works just fine if i use a while loop or a Timer instead, I don't understand what I'm doing wrong. This is the Thread version:
public class Game {
public static void main(String args[]){
Thread t1 = new Thread(new Ball());
Ball ball1 = new Ball();
JFrame frame = new JFrame("Breakout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.WHITE);
frame.setSize(1000, 1000);
frame.setVisible(true);
frame.add(ball1);
t1.start();
}
}
public class Ball extends JPanel implements Runnable{
public int x = 5, y = 5;
public int speedx = 5, speedy = 5;
public int width = 30, height = 30;
public void run() {
while (true){
try {
Physics();
repaint();
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(x, y, width, height);
}
public void Physics(){
x += speedx;
y += speedy;
if(0 > x || x > 1000){
speedx = -speedx;
}
if(0 > y || y > 1000){
speedy = -speedy;
}
}
}

You are using two different Ball objects:
Thread t1 = new Thread(new Ball());
Ball ball1 = new Ball();
Change the order:
Ball ball1 = new Ball();
Thread t1 = new Thread(ball1);

Swing is not thread safe. You have to call repaint from the main thread.

Related

Trouble repainting game with swing timer

This is a follow up to my previous question. I am making Frogger in Java I'm trying to implement a swing timer but it doesn't seem to be working. I'm having some trouble setting it up.
I've tried implementing it in different areas of my code and have come to no conclusion as to what's wrong with it. I followed multiple tutorials and nothing has worked.
private int delay = 7;
public CPT() {
setLayout(new BorderLayout());
label = new JLabel("Frogger");
frame1 = new JFrame("Main");
label.setFont(new Font("Serif", Font.BOLD,50));
label.setBounds(275,10,250,250);
button1 = new JButton("PLAY");
button1.setBounds(300,350,100,50);
button1.setOpaque(false);
button1.setVisible(true);
this.setOpaque(false);
this.setLayout(null);
this.add(label);
button1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame1.setSize(700,500);
frame1.setResizable(false);
button1.setVisible(false);
frame1.add(new TrainCanvas());
frame1.add(p1);
frame1.addKeyListener(new frog());
}
});
this.add(button1);
}
This is the main constructor of my class
class TrainCanvas extends JComponent {
private int lastX = 0;
private int lastX_1 = 0;
private int lastX_2 = 0;
public TrainCanvas() {
// Thread animationThread = new Thread(new Runnable() {
// public void run() {
// while (true) {
// repaint();
// try {Thread.sleep(10);} catch (Exception ex) {}
// }
// }
// });
//
// animationThread.start();
// }
Timer time = new Timer(delay, this {
TrainCanvas.repaint();
});
time.start();
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
int trainW_1 = 100;
int trainH_1 = 5;
int trainSpeed_1 = 3;
int x = lastX + trainSpeed_1;
if (x > w + trainW_1) {
x = -trainW_1;
}
gg.setColor(Color.BLACK);
gg.fillRect(x, h/2 + trainH_1, trainW_1, trainH_1);
lastX = x;
//Draw Frog
frog = new Rectangle(f_x,f_y,25,25);
g3.fill(frog);
g3.setColor(Color.GREEN);
}
}
This is the code that draws the main game I previously used a thread but was told that a swing timer is more useful.
The timer is supposed to repaint my game but it seems as if i can't even implement it properly even though I was told this was right. Any help is appreciated!

how can i make my buttons work? java [duplicate]

This question already has answers here:
Non-static variable cannot be referenced from a static context
(15 answers)
Closed 4 years ago.
I know there are many questions out there regarding action listeners etc.
However, none can help me with my specific issue...no matter which way I try to do it I always get an error.
Here is my simple bouncing ball program:
public class ControlledBall extends JPanel implements Runnable {
int diameter;
long delay;
private int x;
private int y;
private int vx;
private int vy;
public ControlledBall(int xvelocity, int yvelocity) {
diameter = 30;
delay = 40;
x = 1;
y = 1;
vx = xvelocity;
vy = yvelocity;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g.setColor(Color.blue);
g.fillOval(x,y,30,30);
g.setColor(Color.black);
g2.drawOval(x,y,30,30); //draw
}
public void run() {
while(isVisible()) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
System.out.println("Something Went Wrong!");
}
move();
repaint();
}
}
public void move() {
if(x + vx < 0 || x + diameter + vx > getWidth()) {
vx *= -1;
}
if(y + vy < 0 || y + diameter + vy > getHeight()) {
vy *= -1;
}
x += vx;
y += vy;
}
public void stop(){
x=0;
y=0;
}
public class Action implements ActionListener{
public void actionPerformed(ActionEvent e){
stop();
}
}
public static void main(String[] args) {
ControlledBall ball2 = new ControlledBall(12,2);
JFrame window = new JFrame("Controlled Ball");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton stop = new JButton("Stop");
stop.setSize(4,400);
stop.setVisible(true);
stop.setText("Stop");
// stop.addActionListener(new Action());
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
window.add(stop);
JButton start = new JButton("Start");
start.setSize(100,100);
start.setVisible(true);
start.setText("Start");
window.add(start);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
c.ipadx = 400;
c.ipady = 400;
c.gridx = 10;
c.gridy = 10;
window.add(ball2,c);
c.ipadx = 50;
c.ipady = 20;
c.gridx = 10;
c.gridy = 10;
window.pack();
window.setSize(600,600);
window.setLocation(250,200);
window.setVisible(true);
new Thread(ball2).start();
}
}
as you can see by the commented bits I've tried a few different techniques and none have worked. any advice would be greatly appreciated.
Thanks
The main error I get is:
non static field cannot be referenced from a static context
and I assume that's because I'm running it from the main method.
The first thing you really want to do is get rid of your run method (and your reliance on Runnable). This is really an inappropriate way to perform regular updates in Swing.
Swing is single threaded and NOT thread safe, your current approach risks dirty read/writes across thread boundaries.
Instead, you want to use a Swing Timer, see How to Use Swing Timers for more details.
The next thing you want to do is add a start method and update the stop method to support the use of a Swing Timer...
public class ControlledBall extends JPanel {
//...
private Timer timer;
public void stop() {
if (timer == null) {
return;
}
timer.stop();
timer = null;
x = 0;
y = 0;
}
public void start() {
if (timer != null) {
return;
}
timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move();
repaint();
}
});
timer.start();
}
Then, your start and stop buttons just need to be updated to call these methods...
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball2.stop();
}
});
//...
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball2.start();
}
});

java simple animation with threads

I'm looking to create a simple 2D animation using a thread. Once the thread is launched, i'm having trouble figuring out exactly what to put in the run method. Right now, the objects of the Particle class are painted on the frame but there's no animation. Also i could use your help with how to close the thread when the user closes the frame
public class ParticleFieldWithThread extends JPanel implements Runnable{
private ArrayList<Particle> particle = new ArrayList<Particle>();
boolean runnable;
public ParticleFieldWithThread (){
this.setPreferredSize(new Dimension(500,500));
for(int i = 0; i < 100; i++) {
particle.add(new Particle());
}
Thread t1 = new Thread();
t1.start();
}
public void run () {
while (true ) {
try {
Thread.sleep(40);
for (Particle p : particle) {
p.move();
}
repaint();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.RED);
for (Particle p : particle) {
g2.fill(new Rectangle2D.Double(p.getX(), p.getY(), 3, 3));
}
}
public static void main(String[] args) {
final JFrame f = new JFrame("ParticleField");
final ParticleFieldWithThread bb = new ParticleFieldWithThread();
f.setLayout(new FlowLayout());
f.add(bb);
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Here's the particle class
public class Particle {
private double x , y ;
Random r = new Random();
public Particle () {
x = r.nextDouble()*500;
y = r.nextDouble()*500;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void move() {
x += r.nextBoolean() ? 1 : - 1;
y += r.nextBoolean() ? 1 : - 1;
//System.out.println("x : " + x+" y: " + y);
}
}
This does nothing of use:
Thread t1 = new Thread();
t1.start();
You need to pass a Runnable (in your code, it would be the current object of the class, the this) into the Thread's constructor for it to have any meaning or function. i.e.,
Thread t1 = new Thread(this);
t1.start();
For my money, I'd do something completely different and would use a Swing Timer for simple Swing animation.

Java Moving an Object Across the Screen

I am trying to move a train across my java window and am having serious problems. I have a Train class in which I made the train, and a Driver class which is supposed to move the train. I need to make the whole train move from right to left until it 'passes' the left edge of the screen. Then add an if statement to change the dx so the train restarts on the right side . The below is what I have tried but it is not working. Can anyone help me please??
public class Driver extends GraphicsProgram
{
//~ Instance/static variables .............................................
private static final int N_STEPS = 1000;
private static final int PAUSE_TIME = 20;
private static final double TRAIN_LENGTH = 320;
//~ Constructor ...........................................................
// ----------------------------------------------------------
/**
* The run() method of the Driver Class.
* Creates an instance of the Train Class.
* Responsible for animating the train across the screen.
*/
public void run()
{
Train train = new Train(getGCanvas());
for (int i = 0; i < N_STEPS; i++) {
train.move(-100, 0);
pause(PAUSE_TIME);
}
Here is a little demo made with swing. Just replace the black rectangle with an image of your train and you're done.
The trick is to use a separate thread (or timer) to do the animation loop (often called game loop). The loop only tells your window to redraw itself, and on each redraw, you first compute the new positions of the animated objects, then you draw them.
import javax.swing.*;
import java.awt.*;
public class TrainDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("Train Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 400);
frame.setLocationRelativeTo(null);
frame.add(new TrainCanvas());
frame.setVisible(true);
}
}
class TrainCanvas extends JComponent {
private int lastX = 0;
public TrainCanvas() {
Thread animationThread = new Thread(new Runnable() {
public void run() {
while (true) {
repaint();
try {Thread.sleep(10);} catch (Exception ex) {}
}
}
});
animationThread.start();
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
int trainW = 100;
int trainH = 10;
int trainSpeed = 3;
int x = lastX + trainSpeed;
if (x > w + trainW) {
x = -trainW;
}
gg.setColor(Color.BLACK);
gg.fillRect(x, h/2 + trainH, trainW, trainH);
lastX = x;
}
}
color c = color(0); float x = 0; float y = 100; float speed = 1;
void setup() { size(200,200); }
void draw() { background(255); move(); display(); }
void move() { x = x + speed; if (x > width) { x = 0; } }
void display() { fill(c); rect(x,y,30,10); }

Reference of graphics 2d object doesn't work in orphan Thread

I am trying to design a simple game using Graphics2D in a JPanel. I am able to draw normal objects by overriding the paintComponent() method. But when I reference the Graphics2D object inside a orphan Thread, it does not work. Where am I going wrong?
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.drawString("sample",60,100); //Works fine
if(<Certain Condition>){
new Thread(new Runnable(){
//Some Code Here
public void run() {
try{
g2d.drawString("sample2",60,100); //Does not work.. :(
System.out.println("Test Print"); //Shows Output
}
catch (Exception e)
{
}
}
}).start();
}
}
Here is the complete code for reference. This is essentially a 'ping pong ball' game. Its working well but I am not able to highlight an increase in score when the ball hits the striker. The important part of code is highlighted. It's SSCCE.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class MovingBall extends JPanel {
int XPos, YPos;
int speedX, speedY;
int diameter;
private JButton jButton1 = new JButton();
private JButton jButton2 = new JButton();
private JLabel jLabel1 = new JLabel();
private static Timer timer;
private static MovingBall movingball;
private int w,h;
private int strikerHeight;
private int strikerWidth;
private int score;
private boolean isBallMoving;
int strikerYPos;
Graphics2D g2d;
public MovingBall() {
//Striker Properties
strikerHeight = 100;
strikerWidth = 20;
strikerYPos = strikerHeight/2;
//Ball Properties
isBallMoving = false;
XPos = strikerWidth + 5;
YPos = 0;
Random r = new Random();
speedX = 2+ Math.abs(r.nextInt()) % 5;
speedY = 2+ Math.abs(r.nextInt()) % 5;
diameter = 50;
//UI Objects
try {
jbInit();
} catch (Exception e) {
e.printStackTrace();
}
movingball = this; //Helps to access the current class object in inner classes
//Create a timer for animation
timer = new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
movingball.repaint();
}
});
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
Dimension size = getSize();
Insets insets = getInsets();
w = size.width - insets.left - insets.right;
h = size.height - insets.top - insets.bottom;
//Paint the striker
g2d.setColor(Color.DARK_GRAY);
if(strikerYPos < strikerHeight/2) //Top End
g2d.fillRect(0,0, strikerWidth, strikerHeight);
else if(strikerYPos > (h-strikerHeight/2)) //Bottom End
g2d.fillRect(0,h-strikerHeight, strikerWidth, strikerHeight);
else //Anywhere in the middle
g2d.fillRect(0,strikerYPos - (strikerHeight/2), strikerWidth, strikerHeight);
//Paint the ball
if (isBallMoving) {
XPos += speedX;
YPos += speedY;
g2d.drawOval(XPos, YPos, diameter,diameter);
if((XPos+diameter) >= w)
{
//speedX *= -1;
speedX = ((int)Math.signum((double)speedX))*(-1) * (2+ Math.abs(new Random().nextInt()) % 5);
XPos = w-diameter-1;
}
if(XPos <= strikerWidth)
{
if((YPos+diameter/2) >= (strikerYPos-strikerHeight/2) && (YPos+diameter/2) <= (strikerYPos+strikerHeight/2))
{
score++;
//////////////////////////////////////////////////////////////////////
/////THIS IS THE PART TO FOCUS ON///////////////////////////////////////
/////WHEN THE BALL HITS THE STRIKER, I SHOW A '+1' TEXT FADING UPWARDS FROM THE POINT OF HIT
/////(THIS IS TO HIGHLIGHT A +1 INCREASE IN SCORE)///////////////////
//////NOW SINCE THE BALL MAY HIT THE STRIKER AGAIN BEFORE THE PREVIOUS +1 HAS COMPLETELY FADED,
//////I HAVE MADE THIS SIMPLE THREAD TO CREATE A +1 EVERY TIME THERE IS A HIT. SO THERE CAN BE MULTIPLE
//////+1 ON THE SCREEN.
//-------------------------------SADLY, SOMETHING IS WRONG-------------------
//Print a '+1' to show score increase
new Thread(new Runnable(){
int yStart = strikerYPos;
int fadeLength = 0;
Timer pointTimer;
int MAX_FADE_LEN = 50;
public void run() {
try
{
pointTimer = new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(fadeLength >= MAX_FADE_LEN)
pointTimer.stop();
g2d.setColor(new Color(0,0,0,255));
g2d.setFont(new Font("Times",Font.BOLD,20));
g2d.drawString("+1",60,yStart - fadeLength);
g2d.drawOval(100,100,50,50);
System.out.println("Drawn +1 at x = " + 60 + " y = " + (yStart - fadeLength));
fadeLength++;
}
});
pointTimer.start();
}
catch (Exception e)
{
}
}
}).start();
////////////////THREAD ENDS HERE//////////////////////
}
else
{
score--;
}
//SHOW THE SCORE ON THE LABEL
jLabel1.setText("Score: " + score);
speedX = ((int)Math.signum((double)speedX))*(-1) * (2+ Math.abs(new Random().nextInt()) % 5);
XPos = strikerWidth+1;
}
if(YPos <= 0)
{
speedY = ((int)Math.signum((double)speedY))*(-1) * (2+ Math.abs(new Random().nextInt()) % 5);
YPos = 0;
}
if((YPos+diameter) >= h)
{
speedY = ((int)Math.signum((double)speedY))*(-1) * (2+ Math.abs(new Random().nextInt()) % 5);
YPos = h-diameter;
}
} else {
g2d.drawOval(XPos,YPos,diameter,diameter);
return;
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Magic Ball");
movingball = new MovingBall();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(movingball);
frame.setSize(450, 700);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void jbInit() throws Exception {
jButton1.setText("Start");
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setText("Stop");
jButton2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jLabel1.setText("Score:0");
this.add(jButton1, null);
this.add(jButton2, null);
this.add(jLabel1, null);
this.setBackground(Color.white);
this.addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {
int coordX = e.getX();
if(coordX < 200)
strikerYPos = e.getY();
}
public void mouseDragged(MouseEvent e) {
}
});
}
private void jButton1_actionPerformed(ActionEvent e) {
if(!isBallMoving)
isBallMoving = true;
}
private void jButton2_actionPerformed(ActionEvent e) {
isBallMoving = false;
}
}
everything inside paintComponent is repainted (automatically) on every mouse, key and internall methods implemented in API, then you thread probably never ended, there can be bunch of concurently Threads, nothing is repainted, displayed
output to the Swing GUI must be done on EDT
use Swing Timer instead of new Thread(new Runnable(){
call repaint()
I don't think many people would consider almost 250 LOC to be 'short' (though I must admit I was deliberately vague when writing the SSCCE document). OTOH I adapted my shorter source seen here to an animated example that shows a 'fade effect' on mouse clicks. Adapting it to your needs is left as an exercise for ..you.
This source shows how to change the drawn string over a period of 5 seconds. It uses the same Thread (the EDT) for both the main (bouncing ball) and fade animation.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.*;
class ShapeCollision {
private BufferedImage img;
private Area walls;
int x;
int y;
int xDelta = 3;
int yDelta = 2;
ArrayList<Strike> strikes;
/**
* A method to determine if two instances of Area intersect
*/
public boolean doAreasCollide(Area area1, Area area2) {
boolean collide = false;
Area collide1 = new Area(area1);
collide1.subtract(area2);
if (!collide1.equals(area1)) {
collide = true;
}
Area collide2 = new Area(area2);
collide2.subtract(area1);
if (!collide2.equals(area2)) {
collide = true;
}
return collide;
}
ShapeCollision() {
int w = 400;
int h = 200;
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
final JLabel imageLabel = new JLabel(new ImageIcon(img));
x = w / 2;
y = h / 2;
strikes = new ArrayList<Strike>();
MouseListener strikeListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Strike s = new Strike(e.getPoint(),System.currentTimeMillis());
strikes.add(s);
}
};
imageLabel.addMouseListener(strikeListener);
walls = new Area(new Rectangle(0, 0, w, h));
ActionListener animate = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
animate();
imageLabel.repaint();
}
};
Timer timer = new Timer(50, animate);
timer.start();
JOptionPane.showMessageDialog(null, imageLabel);
timer.stop();
}
public void animate() {
Graphics2D g = img.createGraphics();
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLACK);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
x += xDelta;
y += yDelta;
int s = 15;
Area player = new Area(new Ellipse2D.Double(x, y, s, s));
// Acid test of edge collision;
if (doAreasCollide(player, walls)) {
if (x + s > img.getWidth() || x < 0) {
xDelta *= -1;
}
if (y + s > img.getHeight() || y < 0) {
yDelta *= -1;
}
}
g.setColor(Color.ORANGE);
g.setColor(Color.YELLOW);
g.fill(player);
for (Strike strike : strikes) {
strike.draw(g);
}
g.dispose();
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new ShapeCollision();
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
class Strike {
private Point point;
private long started;
private final long DURATION = 5000;
private boolean expired = false;
Strike(Point point, long time) {
this.point = point;
started = time;
}
public void draw(Graphics g) {
long now = System.currentTimeMillis();
long age = now - started;
if (age>DURATION) {
expired = true;
return;
}
double fraction = 1d-((double)age/(double)DURATION);
int alpha = (int)(fraction*255d);
Color c = new Color(255,255,255,alpha);
g.setColor(c);
String s = point.x + "," + point.y;
g.drawString( s, point.x, point.y );
}
public boolean isExpired() {
return expired;
}
}
As i understand - you save the Graphics2D object into g2d variable and trying to paint something onto it from a separate thread later? If so - don't do it. It is a really bad thing to do. Really.
If you want to modify (animate/change) whatever is painted on your component - simply change the data/model which affects the painting and than repaint the whole component or its modified part (any rectangle within the component bounds).
For example in your example case - keep painted string coordinates outside the paint method and modify them in a separate thread and then just call repaint on the component each time you change them. With each repaint string will be painted at the updated coordinates.
Also note that repaint might be called outside of the EDT (Event Dispatch Thread) as it will perform the actual repaint in EDT anyway.
Here is some random example of animation:
public class AnimationTest
{
private static List<Point> locationData = new ArrayList<Point> ();
private static List<Boolean> directionData = new ArrayList<Boolean> ();
public static void main ( String[] args )
{
locationData.add ( new Point ( 5, 25 ) );
directionData.add ( true );
final JComponent canvas = new JComponent ()
{
protected void paintComponent ( Graphics g )
{
super.paintComponent ( g );
Graphics2D g2d = ( Graphics2D ) g;
for ( int i = 0; i < locationData.size (); i++ )
{
Point p = locationData.get ( i );
g2d.drawString ( "Some string #" + i, p.x, p.y );
}
}
};
canvas.addMouseListener ( new MouseAdapter ()
{
public void mousePressed ( MouseEvent e )
{
locationData.add ( e.getPoint () );
directionData.add ( true );
canvas.repaint ();
}
} );
JFrame frame = new JFrame ();
frame.getContentPane ().setLayout ( new BorderLayout () );
frame.getContentPane ().add ( canvas );
frame.setSize ( 500, 500 );
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
Timer timer = new Timer ( 1000 / 48, new ActionListener ()
{
public void actionPerformed ( ActionEvent e )
{
for ( int i = 0; i < locationData.size (); i++ )
{
Point p = locationData.get ( i );
if ( directionData.get ( i ) )
{
if ( p.y < canvas.getHeight () - 1 )
{
p.y += 1;
}
else
{
directionData.set ( i, false );
}
}
else
{
if ( p.y > 20 )
{
p.y -= 1;
}
else
{
directionData.set ( i, true );
}
}
}
canvas.repaint ();
}
} );
timer.start ();
}
}
You can find here:
Data lists on which painting and animation are based with single initial element
Data modification through mouse interaction
Proper canvas update on any data changes
Example is not too optimized, but should be enough to understand the concept.
Print the graphicsobject, if it changes between calls in paintComponent it means the one you are passing to the orphan thread is a dead object which swing doesn't use anymore for painting on the current component.
Swing is a platform-independent, Model-View-Controller GUI framework for Java, which follows a single-threaded programming model.
You should use dispatcher. http://en.wikipedia.org/wiki/Event_Dispatch_Thread

Categories

Resources