简体   繁体   中英

Awt/Swing - Frame doesn't repaint during move process

I'm trying to create an example with some graphics for a ´Stack´. I want the Wagons to "Spawn" and move in one track which are the ´stacks´. The moving process is made by the ´Wagon´ itself. I already tried to give the Wagon a reference to my ´Frame´ called ´Window´ to repaint it in every loop but it still doesn't show up until it reached it's stop.

Wagon:

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


public class Window extends JFrame {

private Stack stack1 = new Stack(1);

public Window() {
    setSize(800, 400);
    setResizable(false);
    setLayout(null); //Not perfect, but it works for those little things
    setVisible(true);
    createTracks(); //Tracksgraphic made out of gray rects
}
public void addWagon(Wagon wagon) { //Is called when adding a Wagon
    this.add(wagon);
    stack1.addWagon(wagon);
}

public static void main(String[] args) { //main
    new Window();
}
}

Stack:

public class Stack {        

private int gleis; //gleis = german for track
private Wagon first = null;


public Stack(int g) {
    gleis = g;
}

public void addWagon(Wagon wagon) {
    if (first != null) {
        wagon.setNext(first);
    }
    first = wagon;
    first.moveRight(gleis);
}

public void removeWagon(int id, Stack nextStack) {
    Wagon speicherFirst = first;
    first.moveLeft(null);
    first = first.getNext();

    while (speicherFirst.getID() != id) {
        speicherFirst.setNext(first);
        first.moveLeft(speicherFirst);
        speicherFirst = first;
        first = first.getNext();
    }

    nextStack.addWagon(speicherFirst);

    if (speicherFirst.getNext() != null) {
        speicherFirst = speicherFirst.getNext();
        while (speicherFirst!= null) {
            speicherFirst.moveRight(gleis);
            speicherFirst = speicherFirst.getNext();
        }
    }
}
public boolean hasID(int id) {
    return first.isID(id);
}
}

Wagon:

import javax.swing.*;
import java.awt.*;
import java.util.Random;


public class Wagon extends JPanel {     //Entspricht einem Canvas aus .awt 

private Wagon next;
private int id;

public Wagon(int i) {
    id = i;
    setSize(50, 20);
    Random r = new Random();
    setBackground(new Color(r.nextFloat(), r.nextFloat(), r.nextFloat()));
    setVisible(true);
}

public boolean isID(int i) {
    if (id == i) {
        return true;
    } else if (next == null) {
        return false;
    } else {
        return next.isID(i);
    }
}

public void setNext(Wagon n) {
    next = n;
}

public void moveRight(int gleis) {
    setLocation(getX(), gleis * 100);
    if (next != null) {
        while (next.getX() - getX() < 70) {
            next.moveRight(gleis);
            move(3);
        }
    } else {
        while (getX() < 700) {
            move(3);
        }
    }
}

public Wagon getNext() {
    return next;
}

public int getID() {
    return id;
}

public void moveLeft(Wagon previous) {

    if (previous == null) {
        while (getX() > 50) {
            move(-3);
        }
    } else {
        while (getX() - previous.getX() > 50) {
            move(-3);
        }
    }
}

public void move(int dir) {
    this.setLocation(getX() + dir, getY());
    try {
        Thread.sleep(20);
    } catch (InterruptedException e) {}
}

}

it still doesn't show up until it reached it's stop.

Your code is executing on the Event Dispatch Thread (EDT), which is the thread that is responsible for handling GUI events and repainting the GUI. The Thread.sleep() prevents the GUI from repainting itself until the while/loop is finished executing so you only see the painting at the end. Read the section from the Swing tutorial on Concurrency for more information.

The solution is to use a Swing Timer to provide the animation, not Thread.sleep().

It looks like you don't actually have the replaint(); call anywhere in your code. I would have that in both the moveLeft() and moveRight() commands.

Another thing, you're using JPanels as your wagons. I wouldn't do this, it'll take more resources and is bad practice. Unless there's a specific reason, I'd use a base sprite image, and load it to an int[] array, and paint that array to that screen using BufferedImage, instead of having x number of JPanel's running around.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM