I am build a graph, with a while circle moving along a line, and stoping over for a few seconds at 3 points of the path. I have managed to do it, however, it does not display the circle moving, it displays only when the circle stops... I can't understand why.
Many thanks in advance for your help
Here is my code:
public class Robot0 extends JFrame implements ActionListener {
public Robot0(String nom, int larg, int haut) {
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
Timer tm = new Timer(10, this);
private int posX = 0;
private int posY = 0;
private int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
tm.start();
}
int segment = 0;
public void actionPerformed(ActionEvent e) {
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0) {
segment = 1;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0) {
segment = 3;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100) {
segment = 6;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
repaint();
}
// Build the Panel
public static void main(String[] args) {
Robot0 r = new Robot0("Robot0", 800, 600);
}
}
Swing is a single Thread library. All painting tasks are executed in the Event Dispatcher Thread
(EDT).
As commented by Andrew Thompson, running long processes (such as sleep) on the EDT makes keeps this thread busy, so it does not do other things
like updating the gui.
The gui becomes unresponsive (freezes).
So the first thing to do is to remove all sleeping.
To park at each stop, use a second timer:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame implements ActionListener {
private static final int PARKING_TIME = 15000;
Timer moveTimer , waitTimer;
private boolean isParking = false;
public Robot0(String nom, int larg, int haut) {
moveTimer = new Timer(10, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private int posX = 0;
private int posY = 0;
private final int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
moveTimer.start();
}
int segment = 0;
@Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0 && segment != 1) { //!=1 so it will not be invoked again
segment = 1;
isParking = true; //flag that robot is parking
waitTimer.start();
return;
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0 && segment !=3) {
segment = 3;
isParking = true;
waitTimer.start();
return;
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100 && segment !=6) {
segment = 6;
isParking = true;
waitTimer.start();
return;
}
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0", 800, 600));
}
}
TODO:
actionPerformed
logicEdit: the following is an implementation with some improvements not necessarily related to question asked:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame {
public Robot0(String nom) {
setTitle(nom);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Floor());
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0"));
}
}
class Floor extends JPanel implements ActionListener{
private static final int PARKING_TIME = 5000, REPAINT_TIME = 10, W = 400, H = 200;
private static final int ROOM_SIZE = 30, ROBOT_SIZE = 20, CROSS_SIZE = 10;
private final Timer moveTimer , waitTimer;
private boolean isParking = false;
private int posX = 0, posY = 0;
private final int velX = 1;
// pathway
private static final int PATH_X[] = { 50, 50, 250, 250, 350, 350 };
private static final int PATH_Y[] = { 50, 150, 150, 50, 50, 150 };
//rooms
private static final Point[] ROOM_CENTERS = {new Point(PATH_X[1],PATH_Y[1]),
new Point(PATH_X[3],PATH_Y[3]),
new Point(PATH_X[5],PATH_Y[5]) };
Floor() {
moveTimer = new Timer(REPAINT_TIME, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
posX = PATH_X[0]; posY = PATH_Y[0];
setPreferredSize(new Dimension(W, H));
moveTimer.start(); //no need to restart with every paint
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawPolyline(PATH_X, PATH_Y, 6);
// draw rooms
g.setColor(Color.GREEN);
for(Point center : ROOM_CENTERS){
drawSquareAround(center, g);
}
//robot
g.setColor(Color.WHITE);
g.fillOval( posX - ROBOT_SIZE/2 , posY - ROBOT_SIZE/2 , ROBOT_SIZE, ROBOT_SIZE);
//cross
g.setColor(Color.RED);
g.drawLine(posX - CROSS_SIZE/2, posY, posX + CROSS_SIZE/2, posY);
g.drawLine(posX, posY - CROSS_SIZE/2, posX, posY + CROSS_SIZE/2);
}
private void drawSquareAround(Point center, Graphics g) {
g.drawRect(center.x - ROOM_SIZE/2, center.y - ROOM_SIZE/2, ROOM_SIZE, ROOM_SIZE);
}
@Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
if (posX <= PATH_X[0] && posY < PATH_Y[1]) {// move along the 1st segment
setPosY(posY + velX);
}else if (posX < PATH_X[2] && posY == PATH_Y[1]) { //move along the second segment
setPosX(posX + velX);
}else if (posX == PATH_X[2] && posY > PATH_Y[3]) { //move along the third segment
setPosY(posY - velX);
}else if (posY == PATH_Y[3] && posX < PATH_X[4]) {// move along the fourth segment
setPosX(posX + velX);
}else if (posX == PATH_X[4] && posY < PATH_Y[5]){// move along the fifth segment
setPosY(posY + velX);
}else {
moveTimer.stop(); //move finished, stop repainting
return;
}
//park if at room center
if(isRoomCeter()){
park();
}
repaint();
}
private void park() {
isParking = true; //flag that robot is parking
waitTimer.start();
}
private boolean isRoomCeter() {
for (Point center : ROOM_CENTERS){
if(posX == center.x && posY == center.y) return true;
}
return false;
}
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}