Reputation: 5
My project has classes Car
and Truck
that inherit from abstract class Vehicle
. Then at random a car or vehicle is to be drawn a total of 10 times. Also, a count of how many of each is to be displayed in a JLabel
, but my counts keep showing up as 0 in the JFrame
. Here is my code.
package vehiclePackage;
import java.awt.Graphics;
import java.util.Random;
public abstract class Vehicle
{
public Vehicle() {
}
public Vehicle(int xLeft, int yTop) {
}
public abstract void draw(Graphics g2);
}
Car
Class:
package vehiclePackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Random;
public class Car extends Vehicle
{
private int xLeft;
private int yTop;
private int ccount;
public Car() { }
public Car (int x, int y)
{
super(x,y);
this.xLeft = x;
this.yTop = y;
}
//@override
public void draw(Graphics g2)
{
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
Color randomColor = new Color(red, green, blue);
Rectangle body = new Rectangle (xLeft, yTop +10, 60, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double (xLeft+10, yTop+20, 10, 10);
Ellipse2D.Double rearTire = new Ellipse2D.Double (xLeft+40, yTop+20, 10, 10);
Point2D.Double r1 = new Point2D.Double(xLeft+10, yTop+10);
Point2D.Double r2 = new Point2D.Double(xLeft+20, yTop);
Point2D.Double r3 = new Point2D.Double(xLeft+40, yTop);
Point2D.Double r4 = new Point2D.Double(xLeft+50, yTop+10);
Line2D.Double frontWindshield = new Line2D.Double(r1,r2);
Line2D.Double roofTop = new Line2D.Double(r2,r3);
Line2D.Double rearWindshield = new Line2D.Double(r3,r4);
((Graphics2D) g2).setColor(randomColor);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(rearTire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(rearTire);
((Graphics2D) g2).draw(frontWindshield);
((Graphics2D) g2).draw(rearWindshield);
((Graphics2D) g2).draw(roofTop);
}
}
Truck
Class:
package vehiclePackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.util.Random;
public class Truck extends Vehicle
{
private int xLeft;
private int yTop;
private int tcount;
public Truck()
{
}
public Truck (int x, int y)
{
super(x, y);
this.xLeft = x;
this.yTop = y;
}
public void draw(Graphics g2)
{
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
Color randomColor = new Color(red, green, blue);
Rectangle body = new Rectangle (xLeft + 22, yTop +10, 60, 20);
Rectangle topCab = new Rectangle(xLeft, yTop + 10, 20, 10);
Rectangle bottomCab = new Rectangle(xLeft, yTop + 20, 20, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double (xLeft+6, yTop+30, 10, 10);
Ellipse2D.Double midTire = new Ellipse2D.Double (xLeft+25, yTop+30, 10, 10);
Ellipse2D.Double mid2Tire = new Ellipse2D.Double (xLeft+35, yTop+30, 10, 10);
Ellipse2D.Double backTire = new Ellipse2D.Double (xLeft+55, yTop+30, 10, 10);
Ellipse2D.Double back2Tire = new Ellipse2D.Double (xLeft+65, yTop+30, 10, 10);
((Graphics2D) g2).setColor(randomColor);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(bottomCab);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(midTire);
((Graphics2D) g2).fill(mid2Tire);
((Graphics2D) g2).fill(backTire);
((Graphics2D) g2).fill(back2Tire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(topCab);
((Graphics2D) g2).draw(bottomCab);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(midTire);
((Graphics2D) g2).draw(mid2Tire);
((Graphics2D) g2).draw(backTire);
((Graphics2D) g2).draw(back2Tire);
}
}
VehicleComponent
Class:
package vehiclePackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
import javax.swing.JComponent;
public class VehicleComponent extends JComponent
{
private int x;
private int y;
private static int ccount = 0;
private static int tcount = 0;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Random rand = new Random();
for (int i = 1; i<=10; i ++)
{
int vehic = rand.nextInt(2);
if (vehic == 0)
{
x = rand.nextInt(420);
y = rand.nextInt(545);
Vehicle car = new Car(x, y);
car.draw(g2);
ccount += 1;
}
if (vehic ==1)
{
x = rand.nextInt(420);
y = rand.nextInt(545);
Vehicle truck = new Truck(x, y);
truck.draw(g2);
tcount += 1;
}
}
}
public String toString()
{
return "Trucks: " + tcount + ", Cars: " + ccount;
}
}
VehicleTester
:
package vehiclePackage;
import java.awt.BorderLayout;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class VehicleViewer {
public static void main(String[] args)
{
// TODO Auto-generated method stub
JFrame f = new JFrame();
f.setSize(500,600);
f.setTitle("Cars and Trucks");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
VehicleComponent component = new VehicleComponent();
f.add(component);
JLabel runningCount = new JLabel(component.toString());
f.add(runningCount, BorderLayout.SOUTH);
f.setVisible(true);
}
}
Upvotes: 0
Views: 1086
Reputation: 347244
What I think you're not understanding is how painting actually works in Swing. Painting is destructive, that is, each time your component is painted, it is expected to completely repaint its entire state, from scratch...
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details...
So you loops in your paintComponent
method, will, if you're really lucky, only ever paint a single vehicle.
Instead, you need to maintain the vehicles in some kind of List
or array and simply let paintComponent
paint the lists...
So, we could change VehicleComponent
thus...
public class VehicleComponent extends JComponent {
private List<Car> cars;
private List<Truck> trucks;
private Random rnd = new Random();
public VehicleComponent() {
cars = new ArrayList<>(25);
trucks = new ArrayList<>(25);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (Car car : cars) {
car.draw(g2);
}
for (Truck truck : trucks) {
truck.draw(g2);
}
}
@Override
public String toString() {
return "Trucks: " + trucks.size() + ", Cars: " + cars.size();
}
}
This will now simply paint whatever is in the cars
and trucks
lists when ever the component is repainted...
Now, the rest assumes I understand your requirements correctly...
Next, we need some way to add new vehicles to the lists...
Not know how you intended to update the component, I wrote this simple method that generates a random number between 0-4
and on 1
it creates a Car
and on 3
it generates a Truck
, you can change this to whatever you like. It checks to see if there is available space in the lists for the new vehicle first before creating them...
public void addNewVehicle() {
int value = (int) Math.round(Math.random() * 5);
if (value == 1) {
if (cars.size() < 10) {
cars.add(new Car(getSize()));
}
} else if (value == 3) {
if (trucks.size() < 10) {
trucks.add(new Truck(getSize()));
}
} else {
System.out.println("No new toys");
}
repaint();
}
To trigger an update, I use a Swing Timer
, which called the addNewVehicle
method every second...
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
component.addNewVehicle();
runningCount.setText(component.toString());
}
});
timer.start();
Adding in the randomised nature of the addNewVehicle
method, this means you won't see a vehicle added every second. This also updates the runningCount
label at the same time, keeping it in sync...
Now, given the nature of painting process, I changed the way your Truck
and Car
paint, instead of randomizing the color each time they are drawn, I randomized the color when each instance is created instead
public class Car extends Vehicle {
private int xLeft;
private int yTop;
private Color color;
public Car(Dimension size) {
xLeft = (int) Math.round((Math.random() * size.width - 60));
yTop = (int) Math.round((Math.random() * size.height - 10));
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
color = new Color(red, green, blue);
}
@Override
public void draw(Graphics g2) {
Rectangle body = new Rectangle(xLeft, yTop + 10, 60, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double(xLeft + 10, yTop + 20, 10, 10);
Ellipse2D.Double rearTire = new Ellipse2D.Double(xLeft + 40, yTop + 20, 10, 10);
Point2D.Double r1 = new Point2D.Double(xLeft + 10, yTop + 10);
Point2D.Double r2 = new Point2D.Double(xLeft + 20, yTop);
Point2D.Double r3 = new Point2D.Double(xLeft + 40, yTop);
Point2D.Double r4 = new Point2D.Double(xLeft + 50, yTop + 10);
Line2D.Double frontWindshield = new Line2D.Double(r1, r2);
Line2D.Double roofTop = new Line2D.Double(r2, r3);
Line2D.Double rearWindshield = new Line2D.Double(r3, r4);
((Graphics2D) g2).setColor(color);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(rearTire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(rearTire);
((Graphics2D) g2).draw(frontWindshield);
((Graphics2D) g2).draw(rearWindshield);
((Graphics2D) g2).draw(roofTop);
}
}
public class Truck extends Vehicle {
private int xLeft;
private int yTop;
private Color color;
public Truck(Dimension size) {
xLeft = (int) Math.round((Math.random() * size.width - 60));
yTop = (int) Math.round((Math.random() * size.height - 20));
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
color = new Color(red, green, blue);
}
@Override
public void draw(Graphics g2) {
Rectangle body = new Rectangle(xLeft + 22, yTop + 10, 60, 20);
Rectangle topCab = new Rectangle(xLeft, yTop + 10, 20, 10);
Rectangle bottomCab = new Rectangle(xLeft, yTop + 20, 20, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double(xLeft + 6, yTop + 30, 10, 10);
Ellipse2D.Double midTire = new Ellipse2D.Double(xLeft + 25, yTop + 30, 10, 10);
Ellipse2D.Double mid2Tire = new Ellipse2D.Double(xLeft + 35, yTop + 30, 10, 10);
Ellipse2D.Double backTire = new Ellipse2D.Double(xLeft + 55, yTop + 30, 10, 10);
Ellipse2D.Double back2Tire = new Ellipse2D.Double(xLeft + 65, yTop + 30, 10, 10);
((Graphics2D) g2).setColor(color);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(bottomCab);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(midTire);
((Graphics2D) g2).fill(mid2Tire);
((Graphics2D) g2).fill(backTire);
((Graphics2D) g2).fill(back2Tire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(topCab);
((Graphics2D) g2).draw(bottomCab);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(midTire);
((Graphics2D) g2).draw(mid2Tire);
((Graphics2D) g2).draw(backTire);
((Graphics2D) g2).draw(back2Tire);
}
}
Now, cause that could be some effort to piece back together, this is the code I used to test it...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final VehicleComponent component = new VehicleComponent();
frame.add(component);
final JLabel runningCount = new JLabel(component.toString());
frame.add(runningCount, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
component.addNewVehicle();
runningCount.setText(component.toString());
}
});
timer.start();
}
});
}
public abstract class Vehicle {
public abstract void draw(Graphics g2);
}
public class Car extends Vehicle {
private int xLeft;
private int yTop;
private Color color;
public Car(Dimension size) {
xLeft = (int) Math.round((Math.random() * size.width - 60));
yTop = (int) Math.round((Math.random() * size.height - 10));
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
color = new Color(red, green, blue);
}
@Override
public void draw(Graphics g2) {
Rectangle body = new Rectangle(xLeft, yTop + 10, 60, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double(xLeft + 10, yTop + 20, 10, 10);
Ellipse2D.Double rearTire = new Ellipse2D.Double(xLeft + 40, yTop + 20, 10, 10);
Point2D.Double r1 = new Point2D.Double(xLeft + 10, yTop + 10);
Point2D.Double r2 = new Point2D.Double(xLeft + 20, yTop);
Point2D.Double r3 = new Point2D.Double(xLeft + 40, yTop);
Point2D.Double r4 = new Point2D.Double(xLeft + 50, yTop + 10);
Line2D.Double frontWindshield = new Line2D.Double(r1, r2);
Line2D.Double roofTop = new Line2D.Double(r2, r3);
Line2D.Double rearWindshield = new Line2D.Double(r3, r4);
((Graphics2D) g2).setColor(color);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(rearTire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(rearTire);
((Graphics2D) g2).draw(frontWindshield);
((Graphics2D) g2).draw(rearWindshield);
((Graphics2D) g2).draw(roofTop);
}
}
public class Truck extends Vehicle {
private int xLeft;
private int yTop;
private Color color;
public Truck(Dimension size) {
xLeft = (int) Math.round((Math.random() * size.width - 60));
yTop = (int) Math.round((Math.random() * size.height - 20));
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
color = new Color(red, green, blue);
}
@Override
public void draw(Graphics g2) {
Rectangle body = new Rectangle(xLeft + 22, yTop + 10, 60, 20);
Rectangle topCab = new Rectangle(xLeft, yTop + 10, 20, 10);
Rectangle bottomCab = new Rectangle(xLeft, yTop + 20, 20, 10);
Ellipse2D.Double frontTire = new Ellipse2D.Double(xLeft + 6, yTop + 30, 10, 10);
Ellipse2D.Double midTire = new Ellipse2D.Double(xLeft + 25, yTop + 30, 10, 10);
Ellipse2D.Double mid2Tire = new Ellipse2D.Double(xLeft + 35, yTop + 30, 10, 10);
Ellipse2D.Double backTire = new Ellipse2D.Double(xLeft + 55, yTop + 30, 10, 10);
Ellipse2D.Double back2Tire = new Ellipse2D.Double(xLeft + 65, yTop + 30, 10, 10);
((Graphics2D) g2).setColor(color);
((Graphics2D) g2).fill(body);
((Graphics2D) g2).fill(bottomCab);
((Graphics2D) g2).fill(frontTire);
((Graphics2D) g2).fill(midTire);
((Graphics2D) g2).fill(mid2Tire);
((Graphics2D) g2).fill(backTire);
((Graphics2D) g2).fill(back2Tire);
((Graphics2D) g2).draw(body);
((Graphics2D) g2).draw(topCab);
((Graphics2D) g2).draw(bottomCab);
((Graphics2D) g2).draw(frontTire);
((Graphics2D) g2).draw(midTire);
((Graphics2D) g2).draw(mid2Tire);
((Graphics2D) g2).draw(backTire);
((Graphics2D) g2).draw(back2Tire);
}
}
public class VehicleComponent extends JComponent {
private int x;
private int y;
private List<Car> cars;
private List<Truck> trucks;
private Random rnd = new Random();
public VehicleComponent() {
cars = new ArrayList<>(25);
trucks = new ArrayList<>(25);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (Car car : cars) {
car.draw(g2);
}
for (Truck truck : trucks) {
truck.draw(g2);
}
}
public void addNewVehicle() {
int value = (int) Math.round(Math.random() * 5);
if (value == 1) {
if (cars.size() < 10) {
cars.add(new Car(getSize()));
}
} else if (value == 3) {
if (trucks.size() < 10) {
trucks.add(new Truck(getSize()));
}
} else {
System.out.println("No new toys");
}
repaint();
}
@Override
public String toString() {
return "Trucks: " + trucks.size() + ", Cars: " + cars.size();
}
}
}
Upvotes: 1
Reputation: 8323
Your problem is you're computing the value for the label text before the paintComponent
routine has been called. Once it's called, the text is left with the old value.
My suggested edit would be to move the figuring of which vehicle to be drawn to the constructor for VehicleComponent
and then when it comes time to draw them, you can look in a pre-populated array to determine what should be drawn, and the counts will already be updated.
See the updates for VehicleComponent
public class VehicleComponent extends JComponent
{
private int x;
private int y;
private int ccount = 0; // these shouldn't be static
private int tcount = 0;
private boolean[] truckOrCar; // simple boolean array (you can change the type as you add more vehicles...)
public VehicleComponent() {
// figure out your car/truck count here
Random rand = new Random();
truckOrCar = new boolean[10];
for (int i = 0; i<10; i ++)
{
int vehic = rand.nextInt(2);
if (vehic == 0)
{
// false for car
truckOrCar[i] = false;
ccount += 1;
}
else {
// true for truck
truckOrCar[i] = true;
tcount += 1;
}
}
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Random rand = new Random();
// here just look in your list for what to draw
for (int i = 0; i<10; i ++)
{
// false for car
if ( !truckOrCar[i] )
{
x = rand.nextInt(420);
y = rand.nextInt(545);
Vehicle car = new Car(x, y);
car.draw(g2);
ccount += 1;
}
// true for truck
else
{
x = rand.nextInt(420);
y = rand.nextInt(545);
Vehicle truck = new Truck(x, y);
truck.draw(g2);
tcount += 1;
}
}
}
public String toString()
{
return "Trucks: " + tcount + ", Cars: " + ccount;
}
}
See result (though your paint coordinates are a little off...):
Upvotes: 1