List C是一个简单的动画小程序,它是一个使用Runnable接口的例子。该例子可以放在网页上,它需要从Applet类中派生出来。该小程序的目的是通过对一个接一个的图象进行着色,从而显示出动画的效果。因为动画占用了不少处理器时间,我们不打算在图象着色的时候阻塞其他进程的运行。例如,假如打算停止动画,我们不想等到它运行结束时,再调用stop方法。换句话说,我们可以让小程序线程化。
List C: 动画小程序
import java.applet.*; import java.awt.*; public class TstRunnable extends Applet implements Runnable { PRivate Thread m_Thread = null; private Image m_Images[]; private Image m_CurrentImage =null; private int m_nImgWidth = 0; private int m_nImgHeight = 0; private boolean m_fAllLoaded = false; private final int NUM_IMAGES = 18; public TstRunnable() { } private void displayImage(Graphics g) { if ( null != m_CurrentImage ) g.drawImage(m_CurrentImage,(getSize().width - m_nImgWidth) / 2, (getSize().height - m_nImgHeight) / 2, null); } public void paint(Graphics g) { if (null != m_CurrentImage) { Rectangle r = g.getClipBounds(); g.clearRect(r.x, r.y, r.width, r.height); displayImage(g); } else g.drawString("Loading images...", 10, 20); } // The Applets start method is called when the page is first shown. public void start() { if (m_Thread == null) { m_Thread = new Thread(this); m_Thread.start(); } } // The Applets stop method is called when the page is hidden. public void stop() { if (m_Thread != null) { m_Thread.stop(); m_Thread = null; } } // The run method is used by the thread // object we created in this start method. public void run() { int iWhichImage = 0; Graphics m_Graphics = getGraphics(); repaint(); m_Graphics = getGraphics(); m_Images = newImage[NUM_IMAGES]; MediaTracker tracker = new MediaTracker(this); String strImage; for (int i = 1; i <= NUM_IMAGES; i++) { m_Images[i-1] = getImage(getCodeBase(), "img" + new Integer(i).toString() + ".gif"); tracker.addImage(m_Images[i-1],0); } try { tracker.waitForAll(); m_fAllLoaded = !tracker.isErrorAny(); } catch (InterruptedException e) {} if (!m_fAllLoaded) { stop(); m_Graphics.drawString("Error loading images!", 10, 40); return; } // Assuming all images are the same // width and height. //------------------------------------ m_nImgWidth = m_Images[0].getWidth(this); m_nImgHeight = m_Images[0].getHeight(this); repaint(); while (true) { try { // Draw next image in animation. m_CurrentImage = m_Images[iWhichImage]; displayImage(m_Graphics); iWhichImage = (iWhichImage+1) % NUM_IMAGES; Thread.sleep(50); } catch (InterruptedException e) { stop(); } } } } 我们使用Runnable接口实现了线程,而没有通过创建线程类的派生类的方式。使用Runnable接口,需要我们实现run方法。我们也需要创建Thread对象的一个实例,它最终是用来调用run方法的。在小程序中的start方法中,我们通过使用thread建构方法产生一个Thread对象的实例,其参数就是实现Runnable接口的任何类。 Thread 对象启动已经定义好的run 方法,而run方法是用来进行动画显示的。当然,从线程类中派生出一个类,并在Applet派生类中创建实例,我们可完成同样的事情。该例子是用来演示Runnable接口的用法。
在我们接着读下去之前,有几个问题需要回答。你也许会问,浏览器调用Java小程序的start和stop方法吗? run 方法是如何被调用的? 情况是这样的,当浏览器启动了一个内部线程时,就相应地启动了applet 的运行。当网页显示时,就启动了applet的start 方法。Start方法创建一个线程对象,并把applet自身传送给线程,以实现run方法。