如何在Java / Swing中使用JLabel制作动画?

我有一个Java课程的最终项目,它是Frog跳跃游戏。 以下是描述它的video:

我不知道如何使用Timer,我只知道Thread.sleep。 但它不起作用。

这是我的代码:

import java.awt.event.ActionListener; import javax.swing.Timer; /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /** * * @author gamekvnn */ public class FrogGame extends javax.swing.JFrame { /** * Creates new form ba */ public FrogGame() { initComponents(); } Timer time; /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") //  private void initComponents() { jPanel1 = new javax.swing.JPanel(); frog1 = new javax.swing.JLabel(); frog2 = new javax.swing.JLabel(); frog3 = new javax.swing.JLabel(); fr0g2 = new javax.swing.JLabel(); fr0g1 = new javax.swing.JLabel(); fr0g3 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); background = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); jPanel1.setLayout(null); frog1.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog1.png")); // NOI18N jPanel1.add(frog1); frog1.setBounds(10, 310, 80, 80); frog2.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog1.png")); // NOI18N jPanel1.add(frog2); frog2.setBounds(110, 310, 80, 80); frog3.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog1.png")); // NOI18N jPanel1.add(frog3); frog3.setBounds(210, 310, 80, 80); fr0g2.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog2.png")); // NOI18N jPanel1.add(fr0g2); fr0g2.setBounds(510, 310, 80, 80); fr0g1.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog2.png")); // NOI18N jPanel1.add(fr0g1); fr0g1.setBounds(610, 310, 80, 80); fr0g3.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/frog2.png")); // NOI18N jPanel1.add(fr0g3); fr0g3.setBounds(410, 310, 80, 80); jButton1.setText("Start"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); jPanel1.add(jButton1); jButton1.setBounds(520, 20, 100, 29); background.setIcon(new javax.swing.ImageIcon("/home/gamekvnn/NetBeansProjects/Project/src/UZKEjzG.png")); // NOI18N jPanel1.add(background); background.setBounds(0, 0, 710, 440); background.getAccessibleContext().setAccessibleName("background"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 708, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE) ); pack(); }//  private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: frog3.setLocation(frog3.getX()+100, frog3.getY()); repaint(); try { Thread.sleep(100);; //1000 milliseconds is one second. } catch(InterruptedException ex) { Thread.currentThread().interrupt(); } fr0g3.setLocation(fr0g3.getX()-200, fr0g3.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g2.setLocation(fr0g2.getX()-100, fr0g2.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog3.setLocation(frog3.getX()+200, frog3.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog2.setLocation(frog2.getX()+200, frog2.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog1.setLocation(frog1.getX()+100, frog1.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g3.setLocation(fr0g3.getX()-200, fr0g3.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g2.setLocation(fr0g2.getX()-200, fr0g2.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g1.setLocation(fr0g1.getX()-200, fr0g1.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog3.setLocation(frog3.getX()+100, frog3.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog2.setLocation(frog2.getX()+200, frog2.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog1.setLocation(frog1.getX()+200, frog1.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g2.setLocation(fr0g2.getX()-100, fr0g2.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } fr0g1.setLocation(fr0g1.getX()-200, frog1.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } frog1.setLocation(frog1.getX()+100, frog1.getY()); repaint(); try { Thread.sleep(100);; } catch (InterruptedException ex) { ex.printStackTrace(); } } /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ // /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(FrogGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(FrogGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(FrogGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(FrogGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } // // /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new FrogGame().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JLabel background; private javax.swing.JLabel fr0g1; private javax.swing.JLabel fr0g2; private javax.swing.JLabel fr0g3; private javax.swing.JLabel frog1; private javax.swing.JLabel frog2; private javax.swing.JLabel frog3; private javax.swing.JButton jButton1; private javax.swing.JPanel jPanel1; // End of variables declaration } 

,我只知道Thread.sleep

好吧,这将无法工作,因为代码正在Event Dispatch Thread (EDT)上执行,这是重新绘制GUI的线程。 因此,如果你一直告诉它睡觉,永远不会有机会重新粉刷自己。

因此,如果您想使用Thread.sleep,则需要启动一个单独的Thread。

有关更多信息,请阅读Swing教程中的并发部分。 也许您也可以使用工作线程教程中讨论的SwingWorker。