第19讲 applet程序设计 1/
教学目标 了解applet的工作原理 掌握创建applet的方法 掌握Applet类的主要方法 掌握applet支持多媒体的技术和方法
applet的创建 可以编写两种类型的applet。一种是使用Applet类来实现,另一种是使用JApplet类来实现的。JApplet类是Applet类的一个直接子类。如果想用Swing集合来实现Applet,那么编写的applet应该继承JApplet类。 要编写一个applet,可以用以下方式创建一个类: import java.applet.*; public class HelloWorld extends Applet {……} HelloWorld类必须为public,且它的名称必须与它所在的文件名匹配,在这里,就是HelloWorld.java.而且,该类必须为java.applet.Applet的子类。
applet的层次结构 Applet类的层次,Java.applet.Applet类实际上是java.awt.Panel的子类。Applet和AWT类的层次如下图所示。
applet的初始化与终止 实际上,与一个应用程序中的方法main()不同的是,没有方法的执行是贯穿于applet的整个生命过程的。 在编写Applet子类时可用的方法有: init(), start(), stop(),destroy()和paint()。 1. public void init() 该方法用于applet的初始化。当applet第一次加载时,该方法会被自动调用。在这个方法中,可以做一些必要的初始化的工作,这些内容包括创建和初始化程序运行所需要的对象实例,把图形或字体载入内存,处理PARAM参数等。
applet的初始化与终止方法 2. public void start() 该方法用来启动浏览器运行applet的主线程。调用init()方法将applet的初始化工作完成之后,start方法会自动调用;当用户刷新包含applet的页面或者从其他页面返回包含applet的页面时,start()方法会被自动调用。 也就是说,start()方法可以被多次调用,这与init()方法是有区别的。基于这样的原因,可以把只调用一次的代码放在init()方法中,而不能放在start()方法中。 3. public void stop() 该方法在用户离开包含applet的页面时会被自动调用。同start()方法,stop()方法也可以被多次调用。当stop()方法被调用时,将停止一些耗费系统资源的活动,如播放动画等。
applet的初始化与终止方法(续) 4. public void destroy() 当用户正常关闭浏览器时,浏览器会调用destroy()方法。该方法用于回收系统资源,如回收图形用户界面的系统资源、关闭连接等。至于applet实例本身,会由浏览器来负责从内存中清除,不需要在destroy()方法中清除。 5.public void paint(Graphics g) 定义在Container类中,applet会自动调用重新绘制画面。 applet类提供的四个方法init()、start()、stop()和destroy()分别对应了applet的初始化、启动、暂停和直到消亡的各个阶段。图10-4说明了applet的生命周期和对应的方法
applet的初始化与终止的方法图示
applet生命周期的一个示例 import java.awt.*; import java.applet.Applet; public class Ex10_2 extends Applet{ public void init(){ System.out.println("init()method called!"); } public void start(){ System.out.println("start() method called!"); } public void stop() { System.out.println("stop() method called!"); } public void destroy() { System.out.println("destroy () method called!"); } public void paint(Graphics g){ g.drawString("Hello World!",50,80); System.out.println("paint() method called!"); } }
applet生命周期的一个示例(续) Ex10_2的运行结果 下面是Ex10_2.htm文件内容: <HTML> <BODY BGLOLOR = "FFFF00"> <APPLET CODE = "Ex10_2.class" WIDTH = "300" HEIGHT = "150"> </APPLET> </BODY> </HTML> Ex10_2的运行结果
applet生命周期的一个示例(续) 程序分析: 在Ex10_2中,设计了一个简单的机制,即利用System.out.println()方法把被调用的init()、start()、stop()、destroy()和paint() 5个方法名输出到Java的控制台用来监控init()、start()、stop()、destroy()与paint()的运行情况。只要这些方法被运行时,在Java的控制台上便会出现哪一个方法被执行。运行Ex10_2.htm后,执行把浏览器缩小、放大、切换页面、刷新等操作,看看这些操作发生时,有哪些方法被调用以及调用的顺序是怎样的。
application与applet application程序有如下主要特点: Java application程序是独立完整的程序 main()方法是Java application程序执行的入口点。 Java applet的一些特点: Java applet程序是在WWW浏览器环境下运行,即不是完整的独立运行程序。 运行Java applet程序的解释器不是独立的软件,而是嵌在WWW浏览器中作为浏览器软件的一部分。 Java applet程序中不需要有main()方法,但是Java applet程序的主类必须是类库中已定义好的类Applet或JApplet的子类。 Java applet程序可以直接利用浏览器或者appletviewer运行图形用户界面,而Java application程序必须另外书写专门代码来创建自己的图形界面。
application与applet的结合示例 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Ex10_3 extends JApplet { public void init(){ Container contentPane = getContentPane(); JLabel label=new JLabel("Application and applet! ",SwingConstants.CENTER); contentPane.add(label);} public static void main(String args[]){ final JFrame f = new JFrame(); JApplet applet = new Ex10_3 (); applet.init(); f.setContentPane(applet.getContentPane()); f.setBounds(50,50,300,200); f.setTitle("Application and applet! "); f.setVisible(true); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); f.addWindowListener(new WindowAdapter(){ public void windowClosed(WindowEvent e){System.exit(0);} }); }}
application与applet的结合示例(续) 图10-6例Ex10_3作为应用程序运行的结果 图10-7 例Ex10_3作为小程序在网页中运行的结果
application与applet的结合示例(续) 程序分析: 其实现思想是这样的,首先创建一个小程序,这个小程序包含一个main()方法,这个main()方法把JFrame实例化,而且还创建这个小程序的一个实例。在调用小程序的init()方法后,窗体用该小程序的内容面板来替代该窗体的内容面板。这个窗体接着设置其边界和标题,并把它的可见性设置为true。如上所示,这种小程序和应用程序的组合实际上是共享一个内容面板。当Ex10_3.java被编译后,它既可作为小程序运行,也可作为应用程序运行。
applet中图像的显示 Java程序运行时,将图像装载到内存里,然后在适合的时机将它显示在屏幕上。 Java特别提供了java.awt.Image类来管理与图像文件有关的信息,因此执行与图像文件有关的操作时需使用import引用这个类。 Image getImage(URL url) Image getImage(URL url,String name) 类 URL 代表一个统一资源定位符,它是指向互联网资源的指针。 boolean drawImage(Image img,int x,int y,ImageObserver observer) 其中,observer参数是一个ImageObserver接口,它用来跟踪图像文件装载是否已经完成的情况,通常都将该参数置为this,即传递本对象的引用去实现这个接口。
applet中图像的显示(续) boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer) 这种格式比第一种格式多了两个参数width和height,即表示图像显示的宽度和高度。若实际图像的高度和宽度与这两个参数值不一样,Java系统会自动将它进行缩放,以适合选定的矩形区域 调用Image类的两个方法就可以分别得到原图的宽度和高度,它们的调用格式如下: int getWidth(ImageObserver observer) int getHeight(ImageObserver observer) 同drawImage()方法一样,通常用this作为observer的参数值。
applet中图像显示的一个示例 例10.4 在applet中加载一个jpg格式图片。 // 文件名Ex10_4.java import java.awt.*; import java.awt.eve中nt.*; import java.applet.Applet; public class Ex10_4 extends Applet{ Image img;//声明Image类型的变量img public void init() { img=getImage(getCodeBase(),"flower.jpg");//加载flower.jpg图片 } public void paint(Graphics g) { g.drawImage(img,40,40,this);//将img画在applet上} } 下面是相应的Ex10_4.htm文件内容: <HTML><BODY BGCLOR = "FFFF00"> <APPLET CODE ="Ex10_4.class" WIDTH =400 HEIGHT=300> </APPLET> </BODY></HTML>
applet中图像显示的一个示例(续) 运行结果: 程序分析: 在Ex10_4.java中,先声明Image类型的变量img,它可用来存放图形影像。然后利用getImage(getCodeBase(),“flower.jpg”)来加载图片flower.jpg,并把加载的图片给变量img,而getCodeBase()是用来取得applet程序所在的目录,因此在本例中,flower.jpg与Ex10_4.java必须置于同一个目录下才能运行。 注意把getImage()命令编写在init()方法中,只要applet一运行,flower.jpg便会自动加载。 最后在paint()方法里,利用drawImage(img,40,40,this)把img加载,并把图像的左上角置于(40,40)处。这里的this关键字代表图片所显示的区域为目前的这个applet。 运行结果:
声音的加载和播放 Java编程语言也具有播放音频文件的方法,这些方法在java.applet.AudioClip类中。利用Java 2中,可以播放WAV、AIFF、MIDI、AU和RMT格式的文件。 播放音频文件的最简单的方式是通过applet的play()方法,有两个形式, play(URL soundDirectory, String soundFile); play(URL soundURL); 例如, play(getDocumentBase(), "bark.au"); 语句将播放存放在与HTML文件相同目录的bark.au,一旦play()方法装载了该声音文件,就立即播放。如果找不到指定URL下的声音文件,play()方法不返回出错信息,只是听不到想听的声音而已。
声音加载和播放的一个示例 例10.5 一个简单的Audio测试 以下的applet在appletviewer运行时中输出消息“Audio Test”,然后播放audio文件sounds/sun.au: //文件名Ex10_5.java //假定存在"sounds/sun.au",sounds与Ex10_5.class在同一个目录 import java.awt.Graphics; import java.applet.applet; public class Ex10_5 extends Applet { public void paint(Graphics g) { g.drawString("Audio Test", 25, 25); play(getDocumentBase(),"sounds/sun.au"); }
声音的加载和播放(续) 由于play()方法只能将声音播放一遍,若想循环播放声音,就需要用到功能更强大的AudioClip类,它能更有效地管理声音的播放操作。因为它被定义在java.applet程序包中,所以需要在程序头部加上: import java.applet.AudioClip; 可以用与装入图像相同的方式装入audio clip(音频剪辑),将它们装载之后进行播放。 为了装入一段audio clip,可使用来自java.applet.applet类的getAudioClip()方法,AudioClip sound; sound = getAudioClip(getDocumentBase(), "bark.au"); 这个方法用来创建一个Audio Clip对象,一旦创建就可以反复播放而无需重装音频文件。 在AudioClip类中与Audio Clip播放有关的方法有:play()、loop()和stop()。
声音的加载和播放示例2 // 文件名Ex10_6 .java // 假定已存在 "sounds/sun.au" import java.awt.Graphics; import java.applet.*; public class Ex10_6 extends Applet { AudioClip sound; public void init() { sound = getAudioClip(getDocumentBase(), "sounds/sun.au"); } public void paint(Graphics g) g.drawString("Audio Test", 25, 25); public void start() { sound.loop();} public void stop() { sound.stop();}
声音的加载和播放示例2(续) 程序分析: 本例中在init()方法中加载需要播放的音乐文件,然后在start()方法中调用loop()方法,则将一段装入的audio自动循环播放,最后在stop()方法中调用类AudioClip的stop()方法停止播放audio。 sound.play(); 播放已装入的udio Clip一遍。每次调用这个方法,audio clip会从头开始播放。 sound. loop(); 循环(自动重放)播放audio clip。 sound. stop(); 停止一段正在播放的audio clip。
动画的生成和播放 Java语言中的动画制作步骤是: 第一步,在屏幕上显示动画的第一帧(也就是第一幅画面); 第二步,每隔很短的时间再显示另外一帧,如此往复。 具体的实现过程是系统去调用repaint( )方法来完成重画任务,而repaint( )方法又去直接调用update( )方法。update( )方法目的是先清除整个applet区域里的内容,然后再调用paint( )方法,从而完成了一次重画工作。 例10.7 在applet中显示一行欢迎标题“Welcome to here!”,但要求这行标题一个字母一个字母跳出来,然后全部隐去,再重复刚才的打字效果。
动画的生成和播放示例 import java.awt.Color; import java.awt.Font; import java.awt.Graphics; public class Ex10_7 extends java.applet.Applet{ String s = "Welcome to Here !"; int s_length = s.length(); //字符串长度 int x_character = 0; //显示到第几个字符 Font wordFont=new Font("TimesRoman" , Font.BOLD , 50); public void start() { while(true) { if (x_character++ > s_length) x_character = 1; repaint (); try{ Thread.sleep(300); //暂停300毫秒 } catch (InterruptedException e) {}}} public void paint (Graphics g) { g.setFont (wordFont); g.setColor (Color.red); g.drawString (s.substring(0,x_character), 8, 50);} }
动画的生成和播放示例(续) 程序分析: 但是这个程序的运行结果并不是想要的结果,因为屏幕上一片空白,什么也没有。原因是程序中调用repaint( )方法时,系统只是得到一个重画的请求,并不是立即去完成重画动作,而系统只能保证当它有空时,才能真正去执行repaint( )方法中的代码,即调用update( )和paint( )方法进行真正的重画工作。 但是在start( )方法中用一个while无穷循环独占了系统资源,系统就没有机会去完成重画工作。同样的道理,本程序也不能正常结束,因为系统同样也没有机会去调用stop( )方法。解决这个问题的方法就是引入多线程机制。
动画的生成和播放示例2 public void stop() { if(runThread!=null) { runThread.stop(); runThread=null;} } public void run() { while(true) { if (x_character++>s_length) x_character = 0; repaint (); try { Thread.sleep(300);} catch (InterruptedException e) {} }} public void paint (Graphics g) { g.setFont (wordFont); g.setColor (Color.red); g.drawString (s.substring(0,x_character), 8, 50); // 文件名Ex10_8.java import java.awt.Color; import java.awt.Font; import java.awt.Graphics; public class Ex10_8 extends java.applet.Applet implements Runnable{ Thread runThread; String s = "Welcome to here !"; int s_length = s.length()-1; int x_character = 0; Font wordFont=new Font("TimesRoman" , Font.BOLD , 50); public void start() { if(runThread==null) { runThread = new Thread(this); runThread.start(); }
动画的生成和播放示例2(续) 程序分析: 该程序实现Runnable接口来实现多线程,然后声明一个Thread类型的实例变量,该实例变量用来存放新的线程对象。其次覆盖start( )方法,在start( )方法中需要生成一个新线程并启动这个线程。再将原来start( )方法中的主循环代码放入run( )方法,也可以说run( )方法中的代码才是这个applet真正的核心。最后覆盖stop( )方法停止这一线程的运行。 这里调用了Thread对象的stop( )方法,就停止了该线程的运行,紧接着将这个Thread对象设为null,让系统把这个无用的Thread当作垃圾收集掉,释放内存。用户如果重新回到该Web页面,applet又会在start( )方法中重新产生新的线程并启动它。这样就达到了预期的效果。
实例1 例10.9 在applet中鼠标点击的位置处显示“Hello World!”的字样。 // 文件名Ex10_9.java import java.awt.*; import java.awt.event.*; import java.applet.Applet; public class Ex10_9 extends Applet implements MouseListener { int mouseX=25; int mouseY=25; public void init () { addMouseListener (this);} public void paint(Graphics g) { g.drawString("Hello World!", mouseX, mouseY); } public void mousePressed(MouseEvent evt) { mouseX = evt.getX(); mouseY = evt.getY(); repaint(); } public void mouseClicked (MouseEvent e) {} public void mouseEntered (MouseEvent e) {} public void mouseExited (MouseEvent e) {} public void mouseReleased (MouseEvent e) {} }
实例2(续) public void paint(Graphics g) { g.drawString("Hello World!", mouseX, mouseY); } public void mousePressed(MouseEvent evt){ mouseX = evt.getX(); mouseY = evt.getY(); repaint(); } public void mouseClicked (MouseEvent e) {} public void mouseEntered (MouseEvent e) {} public void mouseExited (MouseEvent e) {} public void mouseReleased (MouseEvent e) {} } 程序分析: 本例中,首先定义鼠标坐标(25,25),在mousePressed()方法中,先定位鼠标当前点击的位置坐标,再调用repaint()方法重画图形。然后再paint()方法中使用g.drawString("Hello World!", mouseX, mouseY)方法在鼠标点击处显示Hello World!字符串。方法init()中的通过addMouseListener (this)方法注册鼠标监听。
实例2 例10.10 向applet传递参数的范例。 在一个HTML文件中,上下文为<applet>的<param>标记能够为applet传递配置信息。例如: <applet code= Ex10_10.class width=100 height=100> <param name=image value=duke.gif> </applet> 在applet内部,可用方法getParameter()来读取这些值。 // 文件名Ex10_10.java import java.awt.*; import java.applet.*; public class Ex10_10 extends Applet { Image im; public void init() { URL url = getDocumentBase(); String imageName = getParameter( " image " ); im = getImage(url, imageName); } public void paint(Graphics g){ g.drawImage(im, 0, 0, this); } }
实例2(续) 程序分析: 方法getParameter()搜索匹配的名称,并将与之相关的值以字符串的形式返回。如果这个参数名称在位于<applet></applet>标记对中的任何<param>标记中都未找到,则getParameter()返回null。参数的类型都是String。如果你需要其他类型的参数,则必须自己做一些转换处理。例如,读取应为int类型的参数, int speed = Integer.parseInt(getParameter( " speed " )); 由于HTML的本性,参数名称对大小写不敏感;但是,使它们全部为大写或小写是一种良好的风格。如果参数值的字符串中含有空格,则应把整个字符串放入双引号中。值的字符串对大小写敏感;不论是否使用双引号,它们的大小写都保持不变。
本章小结 介绍了applet的基本概念 创建applet小程序的步骤 applet的生命周期及其主要方法:init()、start()、stop()及destroy()四个方法 applet和application的区别和联系 applet对多媒体的支持,包括图像、声音的支持。
本章实训 参考配套实训手册的实训十四 实验目的 通过运行简单的Applet程序,理解Java Applet工作原理,了解Applet的生命周期。 掌握Applet程序的编写方法。 掌握在Java Applet程序中使用文本编辑及按钮控件的方法。 参考配套实训手册的实训十四