1

好像我的图形对象是最终的,因为错误表明我永远无法更改它。在我的计时器循环中使用它们之前,我一直在阅读有关将变量分配给最终变量的信息,以解决这个问题,但我什至不知道如何开始为图形对象处理它。我需要将最终的图形对象复制回普通的图形对象吗?这是一些代码。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.util.ArrayList;

public class Test extends JPanel{

    abstract class graphic {
        public Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        public int[] location = new int[] {screenSize.width/2,screenSize.height/2};
    }

    public class gladiator extends graphic {

        void draw(Graphics g) {

        g.setColor(Color.green);
        g.fillArc(location[0], location[1], 100, 100, 45, 90);
        g.setColor(Color.black);
        g.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);

        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        gladiator[] gladiator = new gladiator[2];
        ArrayList<gladiator> gladiatorList = new ArrayList<gladiator>();
    for (int a =0; a < 2; a++) {
    final gladiator[a] = new gladiator();
    final gladiatorList.add(gladiator[a]);      
    }

        new Timer(200, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (int a = 0; a < gladiatorList.size(); a++) {
                gladiator[a].draw(g);
                }

            repaint();
            System.out.println("repainting");
        }
        }).start();

    }

    public void setLocation(int x, int y){
        //this.location[0] = x;
        //this.location[1] = y;
    }


    public static void main(String[] args){
        JFrame jf=new JFrame();
        jf.setDefaultCloseOperation
        (JFrame.EXIT_ON_CLOSE);
        jf.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
        jf.add(new Test());

        jf.pack();
        jf.setVisible(true);

    }
}

这是返回 for 循环内几乎所有行都应该是最终行的位。

        new Timer(200, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (int a = 0; a < gladiatorList.size(); a++) {
                gladiator[a].draw(g);
                }

            repaint();
            System.out.println("repainting");
        }
        }).start();

谢谢!

4

3 回答 3

2

要在同一方法中定义的匿名类中使用局部变量,必须将局部变量设为 final。

这不会阻止您修改引用变量指向的对象。

在您的情况下,您的匿名类正在使用g,gladiatorgladiatorList. 所以标记所有这些最终:

 protected void paintComponent( final Graphics g) {
    ...

    final gladiator[] gladiator = new gladiator[2];
    final ArrayList<gladiator> gladiatorList = new ArrayList<gladiator>();
于 2013-05-29T14:42:24.330 回答
1

如果您创建变量final,则意味着该变量将始终是对同一对象实例的引用。这并不意味着对象实例的内容不能改变。您不能为该变量分配新的引用,但您可以对实例本身做任何您想做的事情(调用可能修改其状态的方法、读/写字段等)。

于 2013-05-29T14:46:55.573 回答
1

你真的不应该在你paintComponent的 . 您只需将重绘更改sysoutSystem.out.println("repainting in: " + this);

至于Graphics变量的最终性:

final Graphics2D g2d = (Graphics2D) g.create();

g2d在计时器内使用。

编辑:一个完整​​的例子:

public class ExampleAnimationOfMyStuff extends JPanel {

MovingRectangle[] rectangles = new MovingRectangle[20];

public ExampleAnimationOfMyStuff() {
    for (int i = 0; i < rectangles.length; i++) {
        rectangles[i] = new MovingRectangle();
    }
}

public static void main(String[] args) {
    JFrame frame = new JFrame("Animated rectangles");
    ExampleAnimationOfMyStuff anime = new ExampleAnimationOfMyStuff();
    frame.getContentPane().add(anime);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    anime.animate();
    frame.setVisible(true);
}

@Override
@Transient
public Dimension getPreferredSize() {
    return new Dimension(1000, 1000);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    for (MovingRectangle rectangle : rectangles) {
        g.setColor(rectangle.color);
        g.fillRect(rectangle.x, rectangle.y, rectangle.width,
                rectangle.height);
    }
}

public void animate() {
    new Timer(100, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            for (MovingRectangle rectangle : rectangles) {
                rectangle.tick();
            }

            repaint();
            System.out.println("repainting");
        }
    }).start();
}



public static class MovingRectangle extends Rectangle {
    public static Random random = new Random();
    int speedX, speedY;
    Color color;

    public void tick() {
        if (getX() + speedX > 1000 || getX() + speedX < 0) {
            speedX *= -1;
        }

        if (getY() + speedY > 1000 || getY() + speedY < 0) {
            speedY *= -1;
        }

        setRect(getX() + speedX, getY() + speedY, getWidth(), getHeight());
    }

    public MovingRectangle() {
        super(random.nextInt(1000), random.nextInt(1000), random
                .nextInt(40), random.nextInt(40));

        this.speedX = (random.nextDouble() > 0.5) ? 4 : -4;
        this.speedY = (random.nextDouble() > 0.5) ? 4 : -4;
        this.color = new Color(random.nextInt(256), random.nextInt(256),
                random.nextInt(256));
    }
}

}

上面的代码使用一组自定义对象(就像您拥有的那样)将计时器与paintcomponent 分开,无需将事物声明为final,并且还消除了您所经历的闪烁(由于新的计时器触发)。它在屏幕上绘制漂亮的矩形,可以移动;)

在此处输入图像描述

于 2013-05-29T15:02:54.697 回答