Java,程序最后只重新绘制()
我必须在学校做一个作业,它是一个停车场模拟器,叫做run();从main提供了一个完全正常的模拟,其中Carspot每一步都被重新绘制,但是当从actionListener调用它时,它只绘制结果,而不绘制中间的步骤。下面有6个类,其中main在Simulator类中,SimulatorView具有repaint();在里面 那么,有谁能向我解释一下,为什么它在从main调用run()时模拟每个步骤,为什么它在从JButton后面的ActionListener调用run()时只绘制输出 Simulator.java:Java,程序最后只重新绘制(),java,repaint,Java,Repaint,我必须在学校做一个作业,它是一个停车场模拟器,叫做run();从main提供了一个完全正常的模拟,其中Carspot每一步都被重新绘制,但是当从actionListener调用它时,它只绘制结果,而不绘制中间的步骤。下面有6个类,其中main在Simulator类中,SimulatorView具有repaint();在里面 那么,有谁能向我解释一下,为什么它在从main调用run()时模拟每个步骤,为什么它在从JButton后面的ActionListener调用run()时只绘制输出 Simul
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class Simulator implements ActionListener{
private CarQueue entranceCarQueue;
private CarQueue paymentCarQueue;
private CarQueue exitCarQueue;
private SimulatorView simulatorView;
private int day = 0;
private int hour = 0;
private int minute = 0;
private int tickPause = 100;
int weekDayArrivals= 50; // average number of arriving cars per hour
int weekendArrivals = 90; // average number of arriving cars per hour
int enterSpeed = 3; // number of cars that can enter per minute
int paymentSpeed = 10; // number of cars that can pay per minute
int exitSpeed = 9; // number of cars that can leave per minute
public Simulator() {
entranceCarQueue = new CarQueue();
paymentCarQueue = new CarQueue();
exitCarQueue = new CarQueue();
simulatorView = new SimulatorView(3, 6, 30, this);
}
public void run() {
for (int i = 0; i < 10000; i++) {
tick();
}
}
public void run(int steps) {
System.out.println("run " + steps + " steps");
for (int i = 0; i < steps; i++) {
tick();
}
}
private void tick() {
System.out.println("simulator-tick");
// Advance the time by one minute.
minute++;
while (minute > 59) {
minute -= 60;
hour++;
}
while (hour > 23) {
hour -= 24;
day++;
}
while (day > 6) {
day -= 7;
}
Random random = new Random();
// Get the average number of cars that arrive per hour.
int averageNumberOfCarsPerHour = day < 5
? weekDayArrivals
: weekendArrivals;
// Calculate the number of cars that arrive this minute.
double standardDeviation = averageNumberOfCarsPerHour * 0.1;
double numberOfCarsPerHour = averageNumberOfCarsPerHour + random.nextGaussian() * standardDeviation;
int numberOfCarsPerMinute = (int)Math.round(numberOfCarsPerHour / 60);
// Add the cars to the back of the queue.
for (int i = 0; i < numberOfCarsPerMinute; i++) {
Car car = new AdHocCar();
entranceCarQueue.addCar(car);
}
// Remove car from the front of the queue and assign to a parking space.
for (int i = 0; i < enterSpeed; i++) {
Car car = entranceCarQueue.removeCar();
if (car == null) {
break;
}
// Find a space for this car.
Location freeLocation = simulatorView.getFirstFreeLocation();
if (freeLocation != null) {
simulatorView.setCarAt(freeLocation, car);
int stayMinutes = (int) (15 + random.nextFloat() * 10 * 60);
car.setMinutesLeft(stayMinutes);
}
}
// Perform car park tick.
simulatorView.tick();
// Add leaving cars to the exit queue.
while (true) {
Car car = simulatorView.getFirstLeavingCar();
if (car == null) {
break;
}
car.setIsPaying(true);
paymentCarQueue.addCar(car);
}
// Let cars pay.
for (int i = 0; i < paymentSpeed; i++) {
Car car = paymentCarQueue.removeCar();
if (car == null) {
break;
}
// TODO Handle payment.
simulatorView.removeCarAt(car.getLocation());
exitCarQueue.addCar(car);
}
// Let cars leave.
for (int i = 0; i < exitSpeed; i++) {
Car car = exitCarQueue.removeCar();
if (car == null) {
break;
}
// Bye!
}
// Update the car park view.
simulatorView.updateView();
// Pause.
try {
Thread.sleep(tickPause);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void actionPerformed(ActionEvent e)
{
String command = e.getActionCommand();
switch (command) {
case "oneStep":
run(1);
break;
case "hundredSteps":
run(10);
break;
default:
break;
}
}
public static void main (String[] args) {
Simulator start = new Simulator();
}
}
Location.java:
public class Location {
private int floor;
private int row;
private int place;
/**
* Constructor for objects of class Location
*/
public Location(int floor, int row, int place) {
this.floor = floor;
this.row = row;
this.place = place;
}
/**
* Implement content equality.
*/
public boolean equals(Object obj) {
if(obj instanceof Location) {
Location other = (Location) obj;
return floor == other.getFloor() && row == other.getRow() && place == other.getPlace();
}
else {
return false;
}
}
/**
* Return a string of the form floor,row,place.
* @return A string representation of the location.
*/
public String toString() {
return floor + "," + row + "," + place;
}
/**
* Use the 10 bits for each of the floor, row and place
* values. Except for very big car parks, this should give
* a unique hash code for each (floor, row, place) tupel.
* @return A hashcode for the location.
*/
public int hashCode() {
return (floor << 20) + (row << 10) + place;
}
/**
* @return The floor.
*/
public int getFloor() {
return floor;
}
/**
* @return The row.
*/
public int getRow() {
return row;
}
/**
* @return The place.
*/
public int getPlace() {
return place;
}
}
当您从actionListener调用run()时,它将在EventDispatchTread上执行,阻塞该线程,直到run()方法终止。只有在这一点之后,EDT才能对重绘请求进行操作。当您从actionListener调用run()时,它将在EventDispatchTread上执行,阻塞该线程,直到run()方法终止。只有在这一点之后,EDT才能对重新绘制请求进行操作。“通常,Swing不是线程安全的。除非另有说明,否则所有Swing组件和相关类都必须在事件调度线程上访问。”
因此,当执行操作时,actionListener
拾取该事件并在事件调度线程中执行run()
在步骤0,当涉及到repaint()
时,它不会绘制任何内容,因为“在调度所有当前挂起的事件之后,将重新绘制组件。”
repaint()
正在等待发布ActionListener.actionPerformed
到了第1步,同样的事情发生了。只有在最后,在动作事件被释放后,repaint()
才会执行一次。所以这就是为什么只有结果,中间没有步骤
我的建议是将绘制逻辑放在主线程中,而不是actionListener
“通常,Swing不是线程安全的。除非另有说明,否则必须在事件调度线程上访问所有Swing组件和相关类。”
因此,当执行操作时,actionListener
拾取该事件并在事件调度线程中执行run()
在步骤0,当涉及到repaint()
时,它不会绘制任何内容,因为“在调度所有当前挂起的事件之后,将重新绘制组件。”
repaint()
正在等待发布ActionListener.actionPerformed
到了第1步,同样的事情发生了。只有在最后,在动作事件被释放后,repaint()
才会执行一次。所以这就是为什么只有结果,中间没有步骤
我的建议是将绘制逻辑放在主线程中,而不是
actionListener
谢谢@FredK&Max,通过在actionPerformed函数中创建一个新线程来修复它。谢谢@FredK&Max,通过在actionPerformed函数中创建一个新线程来修复它。
public abstract class Car {
private
Location location;
private int minutesLeft;
private boolean isPaying;
/**
* Constructor for objects of class Car
*/
public Car() {
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public int getMinutesLeft() {
return minutesLeft;
}
public void setMinutesLeft(int minutesLeft) {
this.minutesLeft = minutesLeft;
}
public boolean getIsPaying() {
return isPaying;
}
public void setIsPaying(boolean isPaying) {
this.isPaying = isPaying;
}
public void tick() {
System.out.println("car-tick");
minutesLeft--;
}
}
public class Location {
private int floor;
private int row;
private int place;
/**
* Constructor for objects of class Location
*/
public Location(int floor, int row, int place) {
this.floor = floor;
this.row = row;
this.place = place;
}
/**
* Implement content equality.
*/
public boolean equals(Object obj) {
if(obj instanceof Location) {
Location other = (Location) obj;
return floor == other.getFloor() && row == other.getRow() && place == other.getPlace();
}
else {
return false;
}
}
/**
* Return a string of the form floor,row,place.
* @return A string representation of the location.
*/
public String toString() {
return floor + "," + row + "," + place;
}
/**
* Use the 10 bits for each of the floor, row and place
* values. Except for very big car parks, this should give
* a unique hash code for each (floor, row, place) tupel.
* @return A hashcode for the location.
*/
public int hashCode() {
return (floor << 20) + (row << 10) + place;
}
/**
* @return The floor.
*/
public int getFloor() {
return floor;
}
/**
* @return The row.
*/
public int getRow() {
return row;
}
/**
* @return The place.
*/
public int getPlace() {
return place;
}
}
import java.util.LinkedList;
import java.util.Queue;
public class CarQueue {
private Queue<Car> queue = new LinkedList<>();
public boolean addCar(Car car) {
return queue.add(car);
}
public Car removeCar() {
return queue.poll();
}
}
public class AdHocCar extends Car {
public AdHocCar() {
}
}