Java多线程实现简单动画(小球运动)效果

目录

      • 目录
        • 1、多线程的两种实现方式
          • 1.0、关于多线程理解
          • 1.1、Runnable
          • 1.2、Thread
        • 2、实现动画效果的两种方式
          • 2.0、实现过程理解
          • 2.1、画板(JPanel)线程
          • 2.2、物体(Object)线程

1、多线程的两种实现方式

1.0、关于多线程理解

首先,严格按照操作系统理论来说,多线程并没有实现真正的同时进行。而是CPU将工作时间分成很多很短的时间片(Time slicing),每个时刻只能执行一个线程。
Java多线程实现简单动画(小球运动)效果_第1张图片
主要有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口。两种方式,除了创建线程实例的方式有差异外,启动线程都是调用start方法。

1.1、Runnable

Runnable接口中只有一个void run()方法,因此,实现Runnable接口需要实现run()方法。而启动多线程是通过将接口的实现类传入Thread进行实例化,然后调用start()方法。

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

当然也可以通过匿名内部类实现临时的线程:

new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello from a thread!");
    }
}).start(); 

Hint:由于类的继承是单一的,只能有一个父类,因此在类已经继承一个父类时,可以通过实现Runnable接口来实现线程。

1.2、Thread

Thread类本身也是通过实现Runnable接口实现的:

public class Thread extends Object implements Runnable

同样需要重写自己的run方法,启动线程也是调用start方法:

public class HelloThread extends Thread {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        HelloThread p = new HelloThread();
        p.start();
    }
    public static void main(String args[]) {
        (new HelloThread()).start();
    }
}

2、实现动画效果的两种方式

2.0、实现过程理解

实现动画,就是让物体动起来,也就是说每次绘图时有规律的改变物体的位置即可。这里有两种实现方法,一种是将继承JPanel的类作为一个线程,一种是将物体类作为一个线程。两种方式实现效果差别不大,但前者更适用于多个物体一起改变位置的情况(同步),后者适用于物体各自改变位置的情况。

2.1、画板(JPanel)线程

创建一个类,继承JPanel类,实现Runnable接口。在其中重写paint方法,然后实现run()方法,run方法中调用repaint()方法,并使用循环和休眠来实现动画效果。

package test;

import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * MyPanel.java.
 * @author Kaiyan Zhang
 */
public class MyPanel extends JPanel implements Runnable{
  int x = 0,y = 400;
  @Override
  public void paint(Graphics g){
      super.paint(g);
      g.drawOvel(x, y, 20, 20);
  }
  @Override
  public void run(){
      while(true){
          if(x>800)
              x = 0;
          else
              x = x + 10;
          this.repaint();
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
      }
  }

  public static void main(String [] args){
      MyPanel p = new MyPanel();
      /* panel thread, paint the monkey */
      Thread panelThread = new Thread(p);
      JFrame frame = new JFrame();
      frame.add(p);
      frame.setSize(800, 800);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      /* begin to paint */
      panelThread.start();
  }
}

当然,需要绘制的物体也可以作为一个线程,每次改变位置,然后休眠,将物体传入MyPanel进行绘制。这里物体和MyPanel的休眠时间问题,后者的休眠时间更短一些,效果更好。
Hint: 重写paint方法时,一定要先调用父类的paint方法(super.paint(g)),这里后面才能使用repaint进行重写绘制。

2.2、物体(Object)线程

首先实现一个JPanel的子类MyPanel,在paint()方法中实现物体的绘制;然后创建一个运动物体类,继承Thread类,将MyPanel作为参数传入,实现run()方法,当然可以有一个位置成员变量,run方法中每次改变位置后,调用MyPanel.repaint()方法实现新的位置绘图,每次绘制后休眠一段时间。

package test;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * MyPanel.java.
 * @author Kaiyan Zhang
 */
public class MyPanel extends JPanel {
  int x = 0, y = 400;
  Ball b;

  public MyPanel(Ball b) {
    this.b = b;
    b.start();
  }

  @Override
  public void paint(Graphics g) {
    super.paint(g);
    g.drawOvel(b.x, b.y, 20, 20);
  }

  public static void main(String[] args) {
    Ball b = new Ball();
    MyPanel p = new MyPanel(b);
    b.setPanel(p);
    /* panel thread, paint the monkey */
    JFrame frame = new JFrame();
    frame.add(p);
    frame.setSize(800, 800);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  }
}


class Ball extends Thread {
  int x = 0;
  int y = 400;
  MyPanel p;

  public void setPanel(MyPanel p) {
    this.p = p;
  }

  @Override
  public void run() {
    while (true) {
      if (x > 800) {
        x = 0;
      } else {
        x = x + 10;
      }
      p.repaint();
      try {
        sleep(100);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
}

这里给出一个之前写的泡泡龙的代码,每次只有一个球进行运动,即使用该方法实现的
Bubble Shooter-使用线程实现泡泡龙

你可能感兴趣的:(SC)