从ArrayList

时间:2015-11-11 00:13:57

标签: java swing arraylist paint repaint

好的,所以我是Java Swing的新手,也是Java的初学者。我目前的问题是我设计了一个"城市景观"。我正在飞行的飞碟,但随机生成的建筑物继续重建。 我想知道是否有办法将我的建筑物实例保存到我尝试过的ArrayList中,并在每次调用绘制时从该列表中绘制该选择。我尝试了我想到的和我相信它只是在运行时崩溃了,因为它甚至没有打开JFrame,而是在出错时产生错误。这就是我所拥有的:

CityScape类(主类):

import java.awt.*; 
import javax.swing.*;
public class CityScape extends JPanel 
{     
  Buildings a = new Buildings ();
UFO b = new UFO();

  @Override
  public void paint (Graphics g)
  {
    //RememberBuildings.buildingList.get(1).paint(g);
    a.paint(g);
    b.paint(g);
  }
  public void move()
  {
    b.move();
  }


  public static void main(String[] args) throws InterruptedException
  { 
    JFrame frame = new JFrame("Frame"); 
    CityScape jpe = new CityScape();
    frame.add(jpe);
    frame.setSize(800, 750); 
    frame.setBackground(Color.BLACK);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    System.out.println(frame.getContentPane().getSize());
    while (true)
    {
      jpe.move(); //Updates the coordinates
      jpe.repaint(); //Calls the paint method
      Thread.sleep(10); //Pauses for a moment
    }
  }
}

建筑物类(生成建筑物的类):

import java.awt.*;

public class Buildings
{

  private int maxX = 784;
  private int maxY = 712;
  private int width = (int)(Math.random()*100+100);
  private int height = (int)(Math.random()*350+100);
  private  int rows = Math.round((height)/25);
  private int columns = Math.round(width/25);

  public void addBuilding()
  {
  RememberBuildings.addBuilding();
  }

  public void paint(Graphics g) 
  { 
    Graphics2D g2d = (Graphics2D) g;

    Color transYellow = new Color (255, 255, 0, 59);

    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, maxX, maxY);

    g2d.setColor(Color.WHITE);
    g2d.fillRect(5, 5, 25, 25);

    int a = 0;

    for (int i =10; i<634; i+=(a+10))//buildings
    {

      g2d.setColor(Color.GRAY);
      g2d.drawRect(i, maxY-height, width, height);
      g2d.fillRect(i, maxY-height, width, height);


      rows = Math.round((height)/25);
      columns = Math.round(width/25);

      for (int j = 1; j<=columns; j++)//windows
      {
        for (int k = 1; k<=rows; k++)
        {
          g2d.setColor(Color.BLACK);
          g2d.drawRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
          if (Math.random()<0.7)
          {
            g2d.setColor(Color.YELLOW);
            g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
          }
          else
          {
            g2d.setColor(Color.BLACK);
            g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
            g2d.setColor(transYellow);
            g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
          }
        }
      }
      addBuilding();
      a = width;
      height = (int)(Math.random()*462+100);
      width = (int)(Math.random()*100+100);

    }
  }
}

RememberBuildings类(这一点是将实例添加到ArrayList):

import java.util.*;
public class RememberBuildings
{
  public static ArrayList<Buildings> buildingList = new ArrayList<Buildings>();

  public static void addBuilding()
  {
    buildingList.add(new Buildings());
  }
}

最后我的UFO课程(创造飞碟飞行):

import java.awt.*;
import javax.swing.*;
public class UFO extends JPanel
{
  private int x = 20; //x and y coordinates of the ball
  private int y = 20;
  private int xa = 1;
  public void move() //Increase both the x and y coordinates
  {
    if (x + xa < 0) {
      xa = 1;
    }
    if (x + xa > 784-75) 
    {
      xa = -1;
    }
    x = x + xa; 
  }
  public void paint(Graphics g)
  {
    super.paint(g); //Clears the panel, for a fresh start
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.LIGHT_GRAY);
    g2d.fillOval(x,y,75,25); //Draw the ball at the desired point
  }
}

Example

3 个答案:

答案 0 :(得分:3)

  • 避免覆盖paint,请改用paintComponent。在进行任何自定义绘制之前,请始终调用super绘制方法,以确保维护绘制链。有关详细信息,请参阅Painting in AWT and SwingPerforming Custom Painting
  • 请注意,Swing不是线程安全的,从事件调度线程的上下文之外更新任何组件(或组件可能依赖的任何变量)是不明智的。一个简单的解决方案可能是使用Swing Timer而不是while (true)循环和Thread.sleep。有关详细信息,请参阅How to use Swing Timers
  • 您还应该只在事件派发线程的上下文中创建和修改UI组件,有关详细信息,请参阅Initial Threads
  • 如果您的代码无法正常运行,则应考虑提供可显示问题的runnable example。这不是代码转储,而是您正在做的事情的一个示例,它突出了您遇到的问题。这将减少混淆和更好的响应。提供不可运行且缺少类的代码使得很难知道它为什么不起作用以及如何解决它。

答案 1 :(得分:2)

这里有一些事情:

  1. 要解决paintComponent备注并查看示例,请查看此其他主题:Concerns about the function of JPanel: paintcomponent()
  2. 你已经开始的逻辑和面向对象的编程逻辑之间似乎有点脱节,我认为这有助于解决问题(关于OOP的一般信息:https://en.wikipedia.org/wiki/Object-oriented_programming):< / LI>

    你得到了什么:

    你要走的结构如下:

    • CityScape ::这里是您扩展JPanel并设置主要功能
    • 的地方
    • UFO ::代表1 UFO的对象类
    • 构建::一个具有绘制随机建筑物和在RememberBuildings中调用方法的方法的类
    • RememberBuildings ::我认为这是为了追踪已经绘制的建筑物

    这里的问题是你的建筑类的绘画方法不断地绘制多个新随机建筑物而不是保留其结构的建筑物。

    我的建议:

    这个问题有很多解决方案以及实现每个解决方案的不同方法,但我的建议是以OOP方式重新构建您的Building类,这意味着它将代表一个单独的建筑(更真实)到班级的名字)。这将包含一个构造函数,该构造函数初始化该单个构建的所有随机维度,并在jpanel上绘制该单个构建。然后,您需要在包含城市景观一部分的建筑物的城市景观中保留某种数组或列表,从而无需“RememberBuildings”类。粗略地说:

    CityScape extends JPanel:
        variables:
            Building[] buildings;    //might be useful to use an arraylist/stack/queue instead of an array depending on implementation
            UFO craft;
    
        constructor:
            setup new Building objects and add to list buildings
            initialize craft to new UFO
    
        paintComponent:
            calls the paint methods for each building & the ufo craft
    
    Building:
        variables:
            int x, y; // position of building
            int height, width; // of this building
    
        constructor:
            initializes x, y // probably needs to be inputed from CityScape with this setup
            calc height and width randomly // stored in this.height/width
    
        paint:
            paints single building based on it's variables
    
    //side-note, you'll probably need getters for the x/y/width to build each building from CityScape
    

    其他一切都应该是一样的。

    祝你好运!

答案 2 :(得分:1)

因此,每次调用Buildings#paint时,它都会重新生成所有构建,这是随机完成的。

public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    Color transYellow = new Color(255, 255, 0, 59);

    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, maxX, maxY);

    g2d.setColor(Color.WHITE);
    g2d.fillRect(5, 5, 25, 25);

    int a = 0;

    for (int i = 10; i < 634; i += (a + 10))//buildings
    {

        g2d.setColor(Color.GRAY);
        g2d.drawRect(i, maxY - height, width, height);
        g2d.fillRect(i, maxY - height, width, height);

        rows = Math.round((height) / 25);
        columns = Math.round(width / 25);

        for (int j = 1; j <= columns; j++)//windows
        {
            for (int k = 1; k <= rows; k++) {
                g2d.setColor(Color.BLACK);
                g2d.drawRect(i + 5 * j + 20 * (j - 1), (maxY - height) + 5 * k + 20 * (k - 1), 20, 20);
                if (Math.random() < 0.7) {
                    g2d.setColor(Color.YELLOW);
                    g2d.fillRect(i + 5 * j + 20 * (j - 1), (maxY - height) + 5 * k + 20 * (k - 1), 20, 20);
                } else {
                    g2d.setColor(Color.BLACK);
                    g2d.fillRect(i + 5 * j + 20 * (j - 1), (maxY - height) + 5 * k + 20 * (k - 1), 20, 20);
                    g2d.setColor(transYellow);
                    g2d.fillRect(i + 5 * j + 20 * (j - 1), (maxY - height) + 5 * k + 20 * (k - 1), 20, 20);
                }
            }
        }
        addBuilding();
        a = width;
        height = (int) (Math.random() * 462 + 100);
        width = (int) (Math.random() * 100 + 100);

    }
}

您可以通过两种方式解决这个问题,您使用的方法取决于您希望实现的目标。您可以将建筑物直接渲染到BufferedImage并在每个绘制周期中绘制它,或者您可以缓存所需的信息以重新创建建筑物。

BufferedImage方法更快,但无法制作动画,因此如果您想以某种方式为建筑物制作动画(使灯光闪烁),则需要建立一系列信息这可以让你简单地重新绘制它们。

我正在寻找第二个,因为您已经询问了如何从ArrayList绘制资产。

我开始翻译你的&#34; paint&#34;将代码编码到虚拟建筑的单一概念中,虚拟建筑也有关于它自己的灯的信息。

public class Building {

    protected static final Color TRANS_YELLOW = new Color(255, 255, 0, 59);

    private int x, y, width, height;
    private List<Light> lights;

    public Building(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;

        lights = new ArrayList<>(25);
        int rows = Math.round((height) / 25);
        int columns = Math.round(width / 25);

        for (int j = 1; j <= columns; j++)//windows
        {
            for (int k = 1; k <= rows; k++) {
                Color color = null;
                if (Math.random() < 0.7) {
                    color = Color.YELLOW;
                } else {
                    color = TRANS_YELLOW;
                }
                lights.add(new Light(x + 5 * j + 20 * (j - 1), y + 5 * k + 20 * (k - 1), color));
            }
        }
    }

    public void paint(Graphics2D g2d) {
        g2d.setColor(Color.GRAY);
        g2d.drawRect(x, y, width, height);
        g2d.fillRect(x, y, width, height);
        for (Light light : lights) {
            light.paint(g2d);
        }
    }

    public class Light {

        private int x, y;
        private Color color;

        public Light(int x, int y, Color color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public void paint(Graphics2D g2d) {
            g2d.setColor(Color.BLACK);
            g2d.fillRect(x, y, 20, 20);
            g2d.setColor(color);
            g2d.fillRect(x, y, 20, 20);
        }
    }

}

这允许您生成Building的主要参数并简单地缓存结果,并在需要时简单地绘制它。

例如......

public class Buildings {

    private int maxX = 784;
    private int maxY = 712;

    private List<Building> buildings;

    public Buildings() {
        buildings = new ArrayList<>(25);
        for (int i = 10; i < 634; i += 10)//buildings
        {
            int width = (int) (Math.random() * 100 + 100);
            int height = (int) (Math.random() * 350 + 100);
            int x = i;
            int y = maxY - height;

            buildings.add(new Building(x, y, width, height));
        }
    }

    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        for (Building building : buildings) {
            building.paint(g2d);
        }
    }
}

我还更改了您的UFO课程,因此它不再从JPanel延伸,因为它不需要,而且可能是与您的绘画混淆的主要原因。

然后,我在paint更新了您的CityScape方法以使用paintComponent代替...

public class CityScape extends JPanel {

    Buildings a = new Buildings();
    UFO b = new UFO();

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        a.paint(g);
        b.paint(g);
    }

作为一个可运行的例子......

City Scape

import java.awt.Color;
import java.awt.EventQueue;
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class CityScape extends JPanel {

    Buildings a = new Buildings();
    UFO b = new UFO();

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
        a.paint(g);
        b.paint(g);
    }

    public void move() {
        b.move();
    }

    public static void main(String[] args) throws InterruptedException {
        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("Frame");
                CityScape jpe = new CityScape();
                frame.add(jpe);
                frame.setSize(800, 750);
                frame.setBackground(Color.BLACK);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                System.out.println(frame.getContentPane().getSize());

                Timer timer = new Timer(10, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        jpe.move(); //Updates the coordinates
                        jpe.repaint(); //Calls the paint method
                    }
                });
                timer.start();
            }
        });
    }

    public class Buildings {

        private int maxX = 784;
        private int maxY = 712;

        private List<Building> buildings;

        public Buildings() {
            buildings = new ArrayList<>(25);
            for (int i = 10; i < 634; i += 10)//buildings
            {
                int width = (int) (Math.random() * 100 + 100);
                int height = (int) (Math.random() * 350 + 100);
                int x = i;
                int y = maxY - height;

                buildings.add(new Building(x, y, width, height));
            }
        }

        public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            for (Building building : buildings) {
                building.paint(g2d);
            }
        }
    }

    public static class Building {

        protected static final Color TRANS_YELLOW = new Color(255, 255, 0, 59);

        private int x, y, width, height;
        private List<Light> lights;

        public Building(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;

            lights = new ArrayList<>(25);
            int rows = Math.round((height) / 25);
            int columns = Math.round(width / 25);

            for (int j = 1; j <= columns; j++)//windows
            {
                for (int k = 1; k <= rows; k++) {
                    Color color = null;
                    if (Math.random() < 0.7) {
                        color = Color.YELLOW;
                    } else {
                        color = TRANS_YELLOW;
                    }
                    lights.add(new Light(x + 5 * j + 20 * (j - 1), y + 5 * k + 20 * (k - 1), color));
                }
            }
        }

        public void paint(Graphics2D g2d) {
            g2d.setColor(Color.GRAY);
            g2d.drawRect(x, y, width, height);
            g2d.fillRect(x, y, width, height);
            for (Light light : lights) {
                light.paint(g2d);
            }
        }

        public class Light {

            private int x, y;
            private Color color;

            public Light(int x, int y, Color color) {
                this.x = x;
                this.y = y;
                this.color = color;
            }

            public void paint(Graphics2D g2d) {
                g2d.setColor(Color.BLACK);
                g2d.fillRect(x, y, 20, 20);
                g2d.setColor(color);
                g2d.fillRect(x, y, 20, 20);
            }
        }

    }

    public class UFO {

        private int x = 20; //x and y coordinates of the ball
        private int y = 20;
        private int xa = 1;

        public void move() //Increase both the x and y coordinates
        {
            if (x + xa < 0) {
                xa = 1;
            }
            if (x + xa > 784 - 75) {
                xa = -1;
            }
            x = x + xa;
        }

        public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.fillOval(x, y, 75, 25); //Draw the ball at the desired point
        }
    }
}