Moving an object using a thread problem

Hi,

i am having a problem with threads.

In the following code a blue JLabel is moved from the left to the right side of a JPanel and back again.Then the movement starts again.

This seems easy to realize. But it only works if i set a "System.out.println(...)"

inside the run() method of the Thread. Else, the label moves from left to right and back again, but then there is no more continously movement. The label gets a little bit to the right but comes back again quickly and tries again - altough it should go to the right in a slow motion.

Here is the code(can be compiled in one File, named: Test.java):

The most important is MoveThread run() method. If the outputs "forward" and "back" are commented out, the described problem occurs.

Thanks for any explanation in advance, why this happens.

import javax.swing.*;

import javax.swing.border.*;

import java.awt.event.*;

/** Moves the label over the screen (important) */

class MoveThreadextends Thread{

MyLabel myLabel;

public MoveThread(MyLabel myLabel){

this.myLabel = myLabel;

}

publicvoid run(){

while(isInterrupted() ==false){

try{Thread.sleep(100);}catch(InterruptedException ie){}

while(myLabel.getX() < 400){

myLabel.move(0);//forward

System.out.println("forward");

}

while(myLabel.getX() > 0){

myLabel.move(1);//back

System.out.println("back");

}

}

}

}

/** This is the label to move (not important) */

class MyLabelextends JLabel{

JPanel panel;

int i = 0;

int operationPlus = 1;

int operationMinus = -1;

public MyLabel(JPanel panel){

super("Label");

this.panel = panel;

setBackground(java.awt.Color.blue);

setBorder(new LineBorder(java.awt.Color.RED));

setOpaque(true);

}

publicvoid move(int method){

setLocation(getX()+((method == 0)?operationPlus:operationMinus), getY());

panel.repaint();

}

}

/** The label is placed on this panel (not important) */

class MyPanelextends JPanel{

MyLabel myLabel;

MoveThread moveThread;

public MyPanel(){

setLayout(null);

myLabel =new MyLabel(this);

myLabel.setBounds(0,20,50,50);

add(myLabel);

moveThread =new MoveThread(myLabel);

moveThread.start();

}

publicvoid stopThread(){

moveThread.interrupt();

}

}

/** Holds the Panel (not important) */

publicclass Testextends JFrame{

MyPanel myPanel =new MyPanel();

public Test(){

getContentPane().add(myPanel);

addWindowListener(new WindowAdapter(){

publicvoid windowClosing(WindowEvent e){

myPanel.stopThread();

System.exit(0);

}

});

setSize(600,600);

setVisible(true);

}

publicstaticvoid main(String args[]){

Test t =new Test();

}

}

[5878 byte] By [Cinimooda] at [2007-11-26 16:53:24]
# 1
You need to read up on Swing and Threads. Only the event thread is supposed to update Swing components as Swing isn't thread-safe.Try checking a Swing forum to see how to "animate" a label (or achieve the same effect).
davidholmesa at 2007-7-8 23:21:05 > top of Java-index,Core,Core APIs...
# 2

I think It is a better idea to design MoveThread to be scheduled at well defined time slice (in your case each 100ms). The action taken is to move for a pixel in one direction deciding if forward or backward depending of last direction and position of the label. The the thread will suspend again for a time slice. This gives you some benefits:

1) The thread will suspend allowing other threads to do their own work (using System.out causes the thread to suspend for I/O operations, that's because your code works)

2) Varying thread's sleep time you can control speed of label.

That's the code I think:

public void run(){

int direction = 0; //0 means forward, 1 means backward

while(isInterrupted() == false){

try{Thread.sleep(100);}catch(InterruptedException ie){}

if (direction == 0)

{

if (myLabel.getX() >= 400)

{

direction = 1;

}

}

else

{

if (myLabel.getX() <= 0)

{

direction = 0;

}

}

myLabel.move(direction);

}

}

topfoxya at 2007-7-8 23:21:05 > top of Java-index,Core,Core APIs...
# 3
Thanks for your answers. With that code it really works and i understand where the problem is.
Cinimooda at 2007-7-8 23:21:05 > top of Java-index,Core,Core APIs...
# 4

> Thanks for your answers.

> With that code it really works and i understand where

> the problem is.

No it doesn't really work, it just appears to work. You are breaking Swing's single-thread-rule. You might get away with it here, in a given release, on a given platform but its a bug waiting to happen.

What your thread should do is bundle that moveTo logic in a Runnable that it submits to the event thread via invokeLater().

davidholmesa at 2007-7-8 23:21:05 > top of Java-index,Core,Core APIs...