简体   繁体   English

用 swing 绘制多个矩形

[英]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.我试图使用两个不同的类一次在屏幕上绘制 20 个矩形,一个用于框架,一个用于每个矩形,但是只绘制了 1 个。
here is the window class这是 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这是矩形 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. output 只是在框架上绘制了 1 个矩形,而应该是正在绘制 20 个矩形。 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 . JFrame的内容窗格的默认布局管理器是BorderLayout

By default each component is added to the CENTER of the BorderLayout .默认情况下,每个组件都添加到BorderLayoutCENTER 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.要在随机位置显示组件,您需要在内容窗格上使用 null 布局。

  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.您需要将每个组件的大小设置为与首选大小相等,否则默认大小仍为 (0, 0) 并且没有可绘制的内容。

  3. you will need to set the size of each location, otherwise the default will be (0, 0)您需要设置每个位置的大小,否则默认为 (0, 0)

  4. the "random" color of the Vehicle should be assigned in the constructor, not the painting method. Vehicle 的“随机”颜色应该在构造函数中分配,而不是在绘制方法中。 A painting method should only paint the current state, not change the state of the component.一种涂装方法应该只涂装当前的state,不要改变元件的state。

Note:笔记:

This answer only addresses the issues of using a JPanel to represent your Vehicle.此答案仅解决使用 JPanel 表示您的车辆的问题。 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.在这种情况下,因为您在面板上随机定位组件,您需要使用 null 布局并自己设置大小/位置。

This is not the preferred approach.这不是首选方法。 The better approach is to do custom painting yourself of all the Vehicles as demonstrated by Gilbert.更好的方法是自己对所有车辆进行自定义绘画,如 Gilbert 所展示的。

I rearranged your code to create this GUI.我重新排列了您的代码以创建此 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.将代码分成model / view / controller (MVC) 模式是一个非常好的主意。 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.我将您的Vehicle class 制作为可容纳一辆车的普通 Java 吸气剂/设置器 class。

I created a Roadway class to hold the List of Vehicle instances.我创建了一个Roadway class 来保存Vehicle实例List The Roadway class is another plain Java getter / setter class. Roadway class 是另一个普通的 Java 吸气剂/设置剂 class。

I renamed your Window class DrawingPanel and made it a drawing JPanel .我将您的Window class DrawingPanel重命名为绘图JPanel The DrawingPanel class just draws the List of Vehicle instances from the Roadway class. DrawingPanel class 只是从Roadway class 中绘制Vehicle实例List Period.时期。

I created a VehicleListener class to move the vehicles.我创建了一个VehicleListener来移动车辆。

I put the JFrame code into a separate class that calls all the other classes.我将JFrame代码放入一个单独的 class 调用所有其他类。

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;
        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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