简体   繁体   中英

drawing multiple rectangles with swing

im trying to draw 20 rectangles on screen at once using two different classes, one for the frame and one for each rectangle, However only 1 is being drawn.
here is the window class


    private final List<Vehicle> vehicles = new ArrayList<>();

    public Window() {
        this.initWindow();
        this.populateVehicles();
    }

    private void initWindow() {
        this.setSize(1440, 920);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Steering");
        this.setVisible(true);
    }

    public void populateVehicles() {
        for (int i = 0; i < 20; i++) {
            int x = Util.getRandomInt(10, 1000);
            int y = Util.getRandomInt(20, 800);
            Vehicle v = new Vehicle(x, y);
            this.add(v);
            vehicles.add(v);
            System.out.print("printing new rect @ " + x + " : " + y + "\n");
        }
    }

    private void repopulateVehicles() {
        if (this.vehicles.isEmpty()) return;
        for (Vehicle v : vehicles) {
            v.repaint();
        }
    }

    public void refresh(boolean hard) {
        this.repopulateVehicles();
        if (hard) {
            SwingUtilities.updateComponentTreeUI(this);
        }
    }

}

and here is the rectangle class

public class Vehicle extends JPanel {

    private int x;
    private int y;
    private int speed;

    private final int width;
    private final int height;

    public Vehicle(int x, int y) {
        this.x = x;
        this.y = y;
        this.width = 25;
        this.height = 10;
    }

    public void moveVehicle(int x_, int y_) {
        this.x += x_;
        this.y += y_;
        this.repaint(x, y, x_, y_);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        Color c = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
        g2d.setColor(c);
        g2d.rotate(Math.toRadians(30));
        g2d.fillRect(this.x, this.y, this.width, this.height);
    }

    public Dimension getPreferredSize() {
        return new Dimension(this.width, this.height);
    }

}

the output is just 1 rectangle being drawn on the frame, while is should be that 20 rectangles are being drawn. the debug print statement shows that each is being drawn at different coords but they arent being shown.

The default layout manager for the content pane of a JFrame is the BorderLayout .

By default each component is added to the CENTER of the BorderLayout . Only the last component added will be given a size/location. So only the last component will be visible.

The solution is:

  1. to display components at random locations you will need to use a null layout on the content pane.

  2. you will need to set the size of each component equal to the preferred size, otherwise the default size will still be (0, 0) and there is nothing to paint.

  3. you will need to set the size of each location, otherwise the default will be (0, 0)

  4. the "random" color of the Vehicle should be assigned in the constructor, not the painting method. A painting method should only paint the current state, not change the state of the component.

Note:

This answer only addresses the issues of using a JPanel to represent your Vehicle. You need to understand how a layout manager works to give components a size/location. In this case because you are randomly positioning components on the panel you would need to use a null layout and set the size/location yourself.

This is not the preferred approach. The better approach is to do custom painting yourself of all the Vehicles as demonstrated by Gilbert.

I rearranged your code to create this GUI. I shrank it down to fit better in the answer.

转向图形用户界面

It's a really good idea to separate your code into a model / view / controller (MVC) pattern. This allows you to separate your concerns and focus on one part of the application at a time.

I made your Vehicle class a plain Java getter / setter class that holds one vehicle.

I created a Roadway class to hold the List of Vehicle instances. The Roadway class is another plain Java getter / setter class.

I renamed your Window class DrawingPanel and made it a drawing JPanel . The DrawingPanel class just draws the List of Vehicle instances from the Roadway class. Period.

I created a VehicleListener class to move the vehicles.

I put the JFrame code into a separate class that calls all the other classes.

I made all the classes inner classes so I could post the code as one block.

Here's the complete runnable code.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class VehicleGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new VehicleGUI());
    }
    
    private final Dimension drawingPanelDimension;
    
    private DrawingPanel drawingPanel;
    
    private final Roadway roadway;
    
    public VehicleGUI() {
        this.drawingPanelDimension =  new Dimension(400, 200);
        this.roadway = new Roadway(drawingPanelDimension);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Steering");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        this.drawingPanel =  new DrawingPanel(roadway, 
                drawingPanelDimension);
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        Timer timer = new Timer (100, new VehicleListener(this, roadway));
        timer.setInitialDelay(3000);
        timer.start();
    }
    
    public void repaint() {
        drawingPanel.repaint();
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private Roadway roadway;

        public DrawingPanel(Roadway roadway, 
                Dimension drawingPanelDimension) {
            this.roadway = roadway;
            this.setBackground(Color.WHITE);
            this.setPreferredSize(drawingPanelDimension);
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;

            for (Vehicle vehicle : roadway.getVehicles()) {
                g2d.setColor(vehicle.getColor());
                g2d.fillRect(vehicle.getX(), vehicle.getY(), 
                        vehicle.getWidth(), vehicle.getHeight());
            }

        }

    }
    
    public class VehicleListener implements ActionListener {
        
        private final Roadway roadway;
        
        private final VehicleGUI frame;

        public VehicleListener(VehicleGUI frame, Roadway roadway) {
            this.frame = frame;
            this.roadway = roadway;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            for (Vehicle vehicle : roadway.getVehicles()) {
                vehicle.moveVehicle();
            }
            frame.repaint();
        }
        
    }
    
    public class Roadway {
        
        private final Dimension drawingPanelDimension;
        
        private final List<Vehicle> vehicles;
        
        private final Random random;
        
        public Roadway(Dimension drawingPanelDimension) {
            this.drawingPanelDimension = drawingPanelDimension;
            this.vehicles = new ArrayList<>();
            this.random = new Random();
            populateVehicles();
        }
        
        private void populateVehicles() {
            int width = drawingPanelDimension.width;
            int height = drawingPanelDimension.height;
            
            for (int i = 0; i < 20; i++) {
                int x = random.nextInt(width - 40) + 20;
                int y = random.nextInt(height - 40) + 20;
                Vehicle v = new Vehicle(x, y, drawingPanelDimension);
                vehicles.add(v);
            }
        }

        public List<Vehicle> getVehicles() {
            return vehicles;
        }
        
    }
    
    public class Vehicle {

        private double x;
        private double y;

        private final int width;
        private final int height;
        
        private double speed;
        
        private final Color color;
        
        private final Dimension drawingPanelDimension;

        public Vehicle(int x, int y, Dimension drawingPanelDimension) {
            this.x = x;
            this.y = y;
            this.width = 25;
            this.height = 10;
            
            this.drawingPanelDimension = drawingPanelDimension;
            
            this.speed = Math.random() * 20.0 - 10.0;
            
            int red = (int) (Math.random() * 128.0);
            int green = (int) (Math.random() * 128.0);
            int blue = (int) (Math.random() * 128.0);
            this.color = new Color(red, green, blue);
        }

        public void moveVehicle() {
            this.x += speed;
            this.x = (this.x < 0) ? drawingPanelDimension.width + this.x : this.x;
            this.x = (this.x > drawingPanelDimension.width) ? 
                    this.x - drawingPanelDimension.width : this.x;
        }

        public int getX() {
            return (int) Math.round(x);
        }

        public int getY() {
            return (int) Math.round(y);
        }

        public int getWidth() {
            return width;
        }

        public int getHeight() {
            return height;
        }

        public Color getColor() {
            return color;
        }

    }

}

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