使用定时器和启动按钮移动一个形状对象数组-Java



调用shape数组的move方法时,我很难让它中的每个元素移动。我希望每10毫秒重新绘制一次面板,使其形状处于新位置。我想在按下启动按钮/计时器启动时执行此操作。我还希望能够使用我的计时器和Jbutton停止来停止这一切。请随时请我对此进行更多解释:)为您的帮助干杯:)

这是我的Shape类

import java.util.Random;
import java.awt.*;
public class Shape{
  private int x;
  private int y;
  private int width;
  private int height;
  private Color colour;
  static final int moveX = 1;
  static final int moveY = 1;
    public void move (){
    x = x + moveX;
    y = y + moveY;
  }

  /**randomRange method that takes in two parameters, low and high
    * Creates a Random generator that returns a random integer within the low and high range set
    */
    public class RandomRange{
  public int randomRange(int low, int high){
    Random generator = new Random();
    return generator.nextInt(high-low) + low;
  }
    }
  /**Shape constructor which sets data fields to random values within a range
    */
  public Shape (){
    RandomRange r = new RandomRange();
    this.width = r.randomRange(10, 30); 
    this.height = width;
    this.x = r.randomRange(0,(400-width));
    this.y = r.randomRange(0,(400-height));

    int red = r.randomRange(0,255);
    int green = r.randomRange(0,255);
    int blue = r.randomRange(0,255);
    colour = new Color (red, green, blue); //creates a new Color colour consisting of random values from red,green and blue
  }
  /**Display method that gets passed a graphics object
    *sets graphics object g to colour and fills oval with the random values set in constructor Shape
    */
  public void display(Graphics g){
    g.setColor(colour);
    g.fillOval(x,y,width,height);
  }
} //end of class

我的ShapePanel类的开始

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ShapePanel extends JPanel{
  Shape [] shapes = new Shape [20]; //array of 20 elements that have references to as many as 20 Shape objects
  DrawingPanel drawPanel;
  private int count;
  private JPanel controlPanel = new JPanel();
  private JTextField showNum = new JTextField(2);
  private JLabel countLabel = new JLabel("Count"); 
  private JButton addShape = new JButton("Add Shape");
  private JButton start = new JButton("Start");
  private JButton stop = new JButton("Stop");
  Timer timer;
  private final int DELAY = 10;
  /**Main method that creates a new JFrame
    *Adds ShapePanel and does main JFrame methods
    */
  public static void main (String [] args){
    JFrame frame = new JFrame ();
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(new ShapePanel());
    frame.pack();
    frame.setVisible(true);
  }
  /**ShapePanel constructor that creates a JPanels controlPanel and drawPanel
    * Adds JTextField showNum for display of how many shapes have been created to controlPanel
    * Adds Jlabel count and addShape to controlPanel
    * Adds controlPanel and drawPanel to ShapePanel
    * Sets control Panel to size 100 x 400
    * Makes new ButtonListener called listener and adds the listener to addShape button
    */
  public ShapePanel(){

    ButtonListener listener = new ButtonListener();
    DrawingPanel drawPanel = new DrawingPanel();
    timer = new Timer (DELAY, listener);
    addShape.addActionListener(listener); //adds a new ButtonListener listener to JButton addShape
    controlPanel.add (addShape); //controlPanel adding
    controlPanel.add (showNum);
    controlPanel.add (countLabel);
    controlPanel.add(start);
    controlPanel.add(stop);
    add (controlPanel); 
    add (drawPanel);

    controlPanel.setPreferredSize(new Dimension(100,400)); 
  }
  /**Inner class of ShapePanel that determines action of button being pressed
    *Converts count to string totalCount and sets JTextField to count
    *Creates a new shape every time button is pressed and increments count
    */
  /**Inner class DrawingPanel which contains a constructor and paint method
    */
  private class DrawingPanel extends JPanel{
    /**Contructor that is set to a size of 400 x 400 pixels
      *Background is set to pink
      */
    public DrawingPanel(){
      setPreferredSize(new Dimension(400,400));
      setBackground(Color.pink);
    }
    /**paintComponent method which calls the paintComponenet method from JPanel
      * For every shape that has been created, it calls the display method with graphics object g from Shape class
      * Once display method is called, the repaint method is called
      */
    public void paintComponent(Graphics g){
      super.paintComponent (g);
      for (int index = 0; index< count; index ++){
        shapes[index].display(g);
      }
      repaint();
    } //end of paintComponent
  } //end of DrawingPanel
  private  class ButtonListener implements ActionListener{
    public void actionPerformed (ActionEvent event){
      String totalCount = Integer.toString(count);
      showNum.setText(totalCount);
      if (event.getSource() == addShape && count<shapes.length){
        //check that count is smaler than length of array, if so add new Shape to the array and count ++, set text of JTextField to display count
        //call the repaint method on drawPanel to update panel diplayed on screen
        Shape shape = new Shape();
        shapes [count] = shape;
        count ++;
      }
        if (event.getSource() == start){ //here is my problem! I want to click the start button and be able to move my objects
          timer.start();
          for (Shape shape: shapes){
            shape.move(); 

          }
        }
        if (event.getSource() == stop){
          timer.stop();
        }
         repaint();
      }
  }
}//end of class

您有很多问题。。。

首先,您将ButtonListenerjavax.swing.Timer一起使用,但在侦听器中,当计时器滴答作响时,您不会实际更新按钮的位置。所以。。。

timer = new Timer(DELAY, buttonListener);

你应该做一些更像。。。

timer = new Timer(DELAY, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        for (Shape shape : shapes) {
            shape.move();
        }
    }
});

其次,您实际上并没有用startstop按钮注册ButtonListener,例如。。。

start.addActionListener(buttonListener);
stop.addActionListener(buttonListener);

第三,你在paintComponent方法中调用repaint,这是一个非常糟糕的主意,绘制应该绘制当前状态,并且不应该做任何可能导致触发任何类型的重新绘制的事情,否则你将陷入一个无限循环,这会消耗你的CPU,直到什么都不会运行。。。

查看如何使用Swing Timers了解更多详细信息

您需要将监听器添加到按钮:

start.addActionListener(listener);

您还应该避免使用同一个监听器来做不同的事情。每个按钮和每个定时器都应该有自己的监听器,只做按下特定按钮时应该发生的事情:

start.addActionListener(new StartMovingActionListener());
stop.addActionListener(new StopMovingActionListener());
timer.addActionListener(new MoveShapesActionListener());

如果您愿意,也可以使用匿名类。但是,一个有一个大的if/else梯形图来知道按下了什么按钮的类是一团糟。

最新更新