Java在循环中绘制移动矩形

标签 java swing awt drawing

我需要绘制在帧之间移动的 AWT/Swing 矩形。

我有一个Playground

public Playground(int sizeX, int sizeY)
{
    frame = new JFrame();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel = new JPanel();
    panel.setSize(sizeX, sizeY);
    panel.setDoubleBuffered(true);

    panel.setVisible(true);
    frame.add(panel);
    frame.pack();
    frame.setSize(sizeX, sizeY);
}

public void refresh()
{
    panel.repaint();
}

public Graphics getGraphics()
{
    return panel.getGraphics();
}

这是应该在其中绘制对象的类:

public class Star {

    private static int size = 10;

    private int posX;
    private int posY;

    public Star(int posX, int posY)
    {
        this.posX = posX;
        this.posY = posY;
    }

    public void paint(Graphics g)
    {
        g.fillRect(posX, posY, size, size);
    }

    public int getPosX() {
        return posX;
    }

    public int getPosY() {
        return posY;
    }
}

这是主要方法:

public static void main(String[] args) {
    Playground playground = new Playground(400, 400);
    Star star = new Star(100, 100);
    Star star2 = new Star(125, 125);
    while(1 == 1)
    {
        playground.refresh();
        star.paint(playground.getGraphics());
        star2.paint(playground.getGraphics());
    }
}

对象被绘制但闪烁,如何阻止它闪烁?

编辑:我通过将刷新方法更改为以下方式解决了一个元素的闪烁问题:

public void refresh()
{
    panel.getGraphics().clearRect(0,0, panel.getWidth(), panel.getHeight());
}

不幸的是,只有一个元素不闪烁,所有其他元素仍在闪烁。

最佳答案

以下是一个单文件 mcve,演示了通过自定义绘画移动(为简单起见旋转)矩形。 单文件意味着您可以将整个代码复制粘贴到一个文件 (AnimateRectangle.java) 中并执行它。

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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class AnimateRectangle {

    private JFrame frame;

    public AnimateRectangle(Model model){

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new MyJPanel(model);
        panel.setDoubleBuffered(true);

        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

    void refresh() {
        frame.repaint();
    }

    public static void main(String[] args) throws InterruptedException {
        Controller controller = new Controller(400, 400);
        while (true) {
            Thread.sleep(1000);
            SwingUtilities.invokeLater(()->controller.animate());
        }
    }
}

//"wires" gui and model 
class Controller{

    private Model model;
    private AnimateRectangle view;

    Controller(int sizeX, int sizeY){

         model = new Model(sizeX, sizeY);
         view = new AnimateRectangle(model);
    }

    void animate() {
        int newAngle = (model.getAngle() < 360 ) ? model.getAngle()+1 : 0 ;
        model.setAngle(newAngle);
        view.refresh();
    }
}

//represents the inforamtion the GUI needs 
class Model{

    int sizeX, sizeY, angle = 0;

    public Model(int sizeX, int sizeY) {
        this.sizeX = sizeX;
        this.sizeY = sizeY;
    }

    int getSizeX() { return sizeX; }

    int getSizeY() {return sizeY;}

    int getAngle() {return angle;}

    //degrees
    void setAngle(int angle) {  this.angle = angle; }
}

//a JPanel with custom paint component 
class MyJPanel extends JPanel {

    private Model model;

    public MyJPanel(Model model) {
        this.model = model;
        setPreferredSize(new Dimension(model.getSizeX(), model.getSizeY()));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(Color.RED);
        int sizeX = model.getSizeX(), sizeY = model.getSizeY();
        g2d.rotate(Math.toRadians(model.getAngle()), sizeX /2, sizeY/2);
        g2d.fillRect(sizeX/4, sizeY/4, sizeX/2, sizeY/2);
    }
}

一个更好选项(请参阅 camickr 评论)是使用 swing Timer 制作动画。为此,请删除 animate() 方法,并将其替换为:

void animateWithTimer(){

    new Timer(1000,new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            int newAngle = (model.getAngle() < 360 ) ? model.getAngle()+1 : 0 ;
            model.setAngle(newAngle);
            view.refresh();
        }
    }).start();
}

并更改main以使用它:

public static void main(String[] args) throws InterruptedException {
    Controller controller = new Controller(400, 400);
    controller.animateWithTimer();
}

关于Java在循环中绘制移动矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52792463/

相关文章:

java - 单击按钮时更改圆圈的颜色

java - Java可以指示字体是否为斜体

java - 在 DB2 中调用 Java 存储过程时出现错误 -4304

java - 方法中 "too many"局部变量的性能影响?

java - 寻找具有超过 1 个连通分量的邻接矩阵的最小生成树

java - JFrame布局管理

Java 3 颜色渐变

java - 使用 joda time 的 JSP 标记格式化 DateTime 对象时出错

java - 仅垂直调整 JTextArea 大小

java - 使用 TextAction 实现带有 actionPerformed 的 JMenu