我创建了一个包含正方形的应用程序,每次碰到框架的边缘时都会反弹。我在应用程序午餐时没有问题,问题是我不知道如何创建多个线程以具有多个正方形在框架内。
我尝试了多种方法,但是我不知道应该在哪里创建线程。
我还注意到,只有当我将正方形直接添加到框架中时才看到该正方形,而当我将其放置在JPanel中时则看不到。

Square.java

public class Square extends JComponent implements ActionListener {

  int width = 20;
  int height = 20;
  double y = Math.random() * 360;
  double x = Math.random() * 360;
  boolean xMax = false;
  boolean yMax = false;
  boolean xMin = true;
  boolean yMin = true;
  Rectangle2D.Double square = new Rectangle2D.Double(x, y, width, height);

  public Square() {
    Timer t = new Timer(2, this);
    t.start();
  }

  public void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    super.paintComponent(g);
    g2.setColor(Color.BLUE);
    g2.fill(square);

    x_y_rules();


  }
  public void x_y_rules() {
    if (xMax == true) {
        x = x - 0.5;
        if (x <= 0) {
            xMax = false;
        }
    } else {
        x = x + 0.5;
        if (x >= this.getWidth()) {
            xMax = true;
        }
    }
    if (yMax == true) {
        y = y - 0.5;
        if (y <= 0) {
            yMax = false;
        }
    } else {
        y = y + 0.5;
        if (y >= this.getHeight()) {
            yMax = true;
        }
    }
    square.setFrame(x, y, width, height);
  }

 @Override
 public void actionPerformed(ActionEvent arg0) {
    repaint();
 }
}


App.java

public class App extends JFrame {

public static void main(String[] args) {
    JFrame jf = new JFrame();
    Square sqr = new Square();
    jf.setSize(400, 400);
    jf.setVisible(true);
    jf.add(sqr);
    jf.setDefaultCloseOperation(EXIT_ON_CLOSE);
    jf.setLocationRelativeTo(null);
 }
}


尽管我在计时器内放置了2的时间,但方块移动得很慢是正常的吗?

最佳答案

问题:


在paintComponent方法内部有程序逻辑,即x_y_rules()方法调用。取出它,因为它不属于该位置,而是放入它所属的Timer的ActionListener代码中。
您可以根据需要为每个Square分配自己的Swing Timer。这并不是真正的线程问题,因为每个Timer的ActionListener将在EDT上运行。
2毫秒是期望在Swing计时器中使用的不切实际的时间片,并且任何计时器都不会运行得那么快。 11至13是最快的期望或期望。
如果您想让精灵移动得更快,请在移动代码中为delta-x和delta-y赋予更大的值。
您的JComponent没有定义首选大小,这可能是为什么它没有显示在JPanel中的原因,因为默认的FlowLayout会将其大小设置为[0,0]。覆盖其getPreferredSize()并使其返回合理的Dimension值。
您在添加所有组件之前(不可以)在JFrame上调用setVisible(true)





  好的,我在正方形类中放置了一个getPrefferedSize(),但是我遇到了一个问题:正方形不是“在一起”,就像它们在单独的面板上弹跳一样


然后,您的程序结构就被破坏了。您确实不希望创建单独的Swing组件,实际上,您的Square类不应扩展JComponent或JPanel。而是


Square应该是一个逻辑类,从无到有扩展(默认对象除外)。
给它一个绘图方法,说public void draw(Graphics g) {....}
创建一个扩展JPanel的类,称为DrawingPanel,并覆盖其paintComponent方法。
给DrawingPanel类一个ArrayList<Square>,以便它可以容纳多个Square对象。
给DrawingPanel类一个Swing计时器
在DrawingPanel类的Timer中,让它更新ArrayList中所有Square的位置,然后调用repaint()
在paintComponent方法中,使用for循环遍历列表中的所有Square,然后调用每个人的draw方法。


例如:

java - 如何与paintComponent()多线程?-LMLPHP

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

@SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
    private static final int PREF_W = 600;
    private static final int PREF_H = PREF_W;
    private static final int TIMER_DELAY = 20;
    private static final Color[] SQUARE_COLOR = { Color.BLUE, Color.CYAN, Color.DARK_GRAY,
            Color.BLACK, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
            Color.PINK, Color.RED, Color.YELLOW };
    List<Square> squareList = new ArrayList<>();

    public DrawingPanel() {
        // create a bunch of squares
        for (int i = 0; i < SQUARE_COLOR.length; i++) {
            squareList.add(new Square(SQUARE_COLOR[i], PREF_W, PREF_H));
        }

        setBackground(Color.WHITE);

        // create and start the timer
        new Timer(TIMER_DELAY, new TimerListener()).start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // simply draw all the squares in the list
        for (Square square : squareList) {
            square.draw(g);
        }
    }

    // set size of JPanel
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // simply iterate through list and move all squares
            for (Square square : squareList) {
                square.move();
            }
            repaint(); // then repaint the GUI
        }
    }

    private static void createAndShowGui() {
        DrawingPanel mainPanel = new DrawingPanel();

        JFrame frame = new JFrame("Drawing Panel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

// this class does *not* extend JPanel or JComponent
class Square {
    public static final int WIDTH = 20;

    // location of Square
    private double sqrX;
    private double sqrY;

    // X and Y speed
    private double deltaX;
    private double deltaY;

    // width and height of DrawingPanel JPanel
    private int dpWidth;
    private int dpHeight;

    // image to draw
    private Image image;

    public Square(Color color, int dpWidth, int dpHeight) {
        this.dpWidth = dpWidth;
        this.dpHeight = dpHeight;

        // create square at random location with random speed
        sqrX = Math.random() * (dpWidth - WIDTH);
        sqrY = Math.random() * (dpHeight - WIDTH);
        deltaX = Math.random() * 10 - 5;
        deltaY = Math.random() * 10 - 5;

        // one way to draw it is to create an image and draw it
        image = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        g.setColor(color);
        g.fillRect(0, 0, WIDTH, WIDTH);
        g.dispose();
    }

    public void move() {

        // check that we're not hitting boundaries
        if (sqrX + deltaX < 0) {
            deltaX = Math.abs(deltaX);
        }
        if (sqrX + deltaX + WIDTH >= dpWidth) {
            deltaX = -Math.abs(deltaX);
        }
        sqrX += deltaX;

        // check that we're not hitting boundaries
        if (sqrY + deltaY < 0) {
            deltaY = Math.abs(deltaY);
        }
        if (sqrY + deltaY + WIDTH >= dpHeight) {
            deltaY = -Math.abs(deltaY);
        }
        sqrY += deltaY;

    }

    public void draw(Graphics g) {
        int x = (int) sqrX;
        int y = (int) sqrY;
        g.drawImage(image, x, y, null);
    }
}

07-24 18:51
查看更多