son2323
son2323

Reputation: 5

Displaying a count using JLabel?

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

Answers (2)

MadProgrammer
MadProgrammer

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

Ryan J
Ryan J

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...):

enter image description here

Upvotes: 1

Related Questions