You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将action方法移至FishAnimation类后Java Swing动画失效求助

问题:动画逻辑迁移到FishAnimation类后失效

将原本在Screen类中的动画action方法剪切到FishAnimation类后,调用fA.action()完全看不到动画效果,但把方法移回Screen类就正常运行,请问原因是什么?

Screen类代码

package main;

import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import AnimatorHandler.FishAnimation;
import data.*;
import save.Data;

public class Screen extends JPanel{
    
    Resources res = new Resources();
    Background background = new Background();
    Ground ground = new Ground();
    Animal animal = new Animal(null, null, 0, null, 0, 0);
    FishAnimation fA = new FishAnimation();
    
    int screenSizeX = 1099;
    int screenSizeY = 735;
    
    void createWindow() throws IOException {
        
        //CREATION OF THE RESOURCES
        background.createBackground();
        ground.createGround();
        animal.createAnimal();
        
        //SETTING OF THE LAYEREDPANE
        JLayeredPane layeredPane = new JLayeredPane();
        layeredPane.setBounds(0, 0, screenSizeX, screenSizeY);
        layeredPane.add(background.background[Data.selectedBackground], Integer.valueOf(0));
        layeredPane.add(ground.ground[Data.selectedGround], Integer.valueOf(1));
        layeredPane.add(animal.animals[Data.selectedAnimal], Integer.valueOf(2));
        layeredPane.add(animal.animals[Data.selectedAnimal+1], Integer.valueOf(2));
           
        //SETTING OF THE FRAME
        JFrame frame = new JFrame("Happy Aquarium");
        frame.add(layeredPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(screenSizeX, screenSizeY));
        frame.setLayout(null);
        frame.setVisible(true);
        
        //ANIMATION
        fA.action();
        
    }
}

FishAnimation类代码

package AnimatorHandler;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.Timer;

import data.Animal;
import save.Data;

public class FishAnimation implements ActionListener{
    
    Animal animal = new Animal(null, null, 0, null, 0, 0);
    Timer timer;
    
    public void action() throws IOException {
        animal.createAnimal();
        
        timer = new Timer(1, this);
        timer.start();
            
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        
        if(animal.animals[Data.selectedAnimal].getY() >= 260 || animal.animals[Data.selectedAnimal].getY()<-300) {
            animal.animali[Data.selectedAnimal].setYVelocity(animal.animali[Data.selectedAnimal].getYVelocity() * -1);
        }
        
        if(animal.animals[Data.selectedAnimal].getX() >= 456 || animal.animals[Data.selectedAnimal].getX()<-456) {
            animal.animali[Data.selectedAnimal].setXVelocity(animal.animali[Data.selectedAnimal].getXVelocity() * -1);
        }
        animal.animals[Data.selectedAnimal].setBounds(animal.animals[Data.selectedAnimal].getX() + animal.animali[Data.selectedAnimal].getXVelocity(), animal.animals[Data.selectedAnimal].getY() + animal.animali[Data.selectedAnimal].getYVelocity(), 1083, 696);

        if(animal.animals[Data.selectedAnimal+1].getY() >= 260 || animal.animals[Data.selectedAnimal+1].getY()<-300) {
            animal.animali[Data.selectedAnimal+1].setYVelocity(animal.animali[Data.selectedAnimal+1].getYVelocity() * -1);
        }
        
        if(animal.animals[Data.selectedAnimal+1].getX() >= 456 || animal.animals[Data.selectedAnimal+1].getX()<-456) {
            animal.animali[Data.selectedAnimal+1].setXVelocity(animal.animali[Data.selectedAnimal+1].getXVelocity() * -1);
        }
        animal.animals[Data.selectedAnimal+1].setBounds(animal.animals[Data.selectedAnimal+1].getX() + animal.animali[Data.selectedAnimal+1].getXVelocity(), animal.animals[Data.selectedAnimal+1].getY() + animal.animali[Data.selectedAnimal+1].getYVelocity(), 1083, 696);
        
    }
}

原因分析

核心问题是操作的对象不一致:

  • Screen类中创建了一个Animal实例,调用animal.createAnimal()后,将这个实例的动物组件添加到了UI的分层面板中,是界面上显示的真实对象。
  • FishAnimation类内部自己new了一个全新的Animal实例,这个实例和Screen里的不是同一个对象,它的组件从未被添加到界面上。
  • FishAnimation的actionPerformed方法一直在修改自己内部这个"隐形"的Animal实例的属性,界面上的真实组件完全没被改动,所以看不到动画效果;而原来在Screen类中时,操作的是同一个被添加到UI的Animal实例,所以动画正常。

修复方案

1. 修改FishAnimation类,接收外部传入的Animal实例

去掉内部自己创建的Animal,通过构造方法传入Screen中的实例:

package AnimatorHandler;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.Timer;

import data.Animal;
import save.Data;

public class FishAnimation implements ActionListener{
    
    private Animal animal; // 改为外部传入
    Timer timer;
    
    // 新增构造方法,接收Animal实例
    public FishAnimation(Animal animal) {
        this.animal = animal;
    }
    
    public void action() throws IOException {
        // 移除animal.createAnimal(),因为Screen中已经初始化过
        timer = new Timer(1, this);
        timer.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 方法内容保持不变,现在操作的是界面上的真实Animal实例
        if(animal.animals[Data.selectedAnimal].getY() >= 260 || animal.animals[Data.selectedAnimal].getY()<-300) {
            animal.animali[Data.selectedAnimal].setYVelocity(animal.animali[Data.selectedAnimal].getYVelocity() * -1);
        }
        
        if(animal.animals[Data.selectedAnimal].getX() >= 456 || animal.animals[Data.selectedAnimal].getX()<-456) {
            animal.animali[Data.selectedAnimal].setXVelocity(animal.animali[Data.selectedAnimal].getXVelocity() * -1);
        }
        animal.animals[Data.selectedAnimal].setBounds(animal.animals[Data.selectedAnimal].getX() + animal.animali[Data.selectedAnimal].getXVelocity(), animal.animals[Data.selectedAnimal].getY() + animal.animali[Data.selectedAnimal].getYVelocity(), 1083, 696);

        if(animal.animals[Data.selectedAnimal+1].getY() >= 260 || animal.animals[Data.selectedAnimal+1].getY()<-300) {
            animal.animali[Data.selectedAnimal+1].setYVelocity(animal.animali[Data.selectedAnimal+1].getYVelocity() * -1);
        }
        
        if(animal.animals[Data.selectedAnimal+1].getX() >= 456 || animal.animals[Data.selectedAnimal+1].getX()<-456) {
            animal.animali[Data.selectedAnimal+1].setXVelocity(animal.animali[Data.selectedAnimal+1].getXVelocity() * -1);
        }
        animal.animals[Data.selectedAnimal+1].setBounds(animal.animals[Data.selectedAnimal+1].getX() + animal.animali[Data.selectedAnimal+1].getXVelocity(), animal.animals[Data.selectedAnimal+1].getY() + animal.animali[Data.selectedAnimal+1].getYVelocity(), 1083, 696);
    }
}

2. 修改Screen类,初始化FishAnimation时传入自己的Animal实例

package main;

import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import AnimatorHandler.FishAnimation;
import data.*;
import save.Data;

public class Screen extends JPanel{
    
    Resources res = new Resources();
    Background background = new Background();
    Ground ground = new Ground();
    Animal animal = new Animal(null, null, 0, null, 0, 0);
    FishAnimation fA; // 先声明,后初始化
    
    int screenSizeX = 1099;
    int screenSizeY = 735;
    
    void createWindow() throws IOException {
        
        //CREATION OF THE RESOURCES
        background.createBackground();
        ground.createGround();
        animal.createAnimal();
        
        // 初始化FishAnimation时传入当前的animal实例
        fA = new FishAnimation(animal);
        
        //SETTING OF THE LAYEREDPANE
        JLayeredPane layeredPane = new JLayeredPane();
        layeredPane.setBounds(0, 0, screenSizeX, screenSizeY);
        layeredPane.add(background.background[Data.selectedBackground], Integer.valueOf(0));
        layeredPane.add(ground.ground[Data.selectedGround], Integer.valueOf(1));
        layeredPane.add(animal.animals[Data.selectedAnimal], Integer.valueOf(2));
        layeredPane.add(animal.animals[Data.selectedAnimal+1], Integer.valueOf(2));
           
        //SETTING OF THE FRAME
        JFrame frame = new JFrame("Happy Aquarium");
        frame.add(layeredPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(screenSizeX, screenSizeY));
        frame.setLayout(null);
        frame.setVisible(true);
        
        //ANIMATION
        fA.action();
        
    }
}

内容的提问来源于stack exchange,提问作者TokenZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:47:32