📄 jv0403.htm
字号:
int s_length = s.length();<br>
int x_character = 0;<br>
Font wordFont=new Font("TimesRoman" , Font.BOLD , 50);<br>
public void start() {<br>
if(runThread==null){<br>
runThread = new Thread(this);<br>
runThread.start();<br>
}<br>
}<br>
public void stop() {<br>
if(runThread!=null){<br>
runThread.stop();<br>
runThread=null;<br>
}<br>
}<br>
public void run() {<br>
while(true) {<br>
if (x_character++>s_length)<br>
x_character = 0;<br>
repaint ();<br>
try {<br>
Thread.sleep(300);<br>
} catch (InterruptedException e) {}<br>
}<br>
}<br>
public void paint (Graphics g) {<br>
g.setFont (wordFont);<br>
g.setColor (Color.red);<br>
g.drawString (s.substring(0,x_character), 8, 50);<br>
}<br>
}</P>
<p> <IMG height=130
src="tu4-16.gif" width=416></P>
<p> </P>
<p> 图4-15 简单动画例子的执行结果</P>
<p> <a name="433"></a>4.3.3 初识闪烁问题</P>
<p> 虽然,我们刚才的applet已经能动起来,可是挑剔的用户马上就会发现屏幕上的动画会一闪一闪的,如果你的机器速度较慢的话,这一现象就更明显。确实,有效的解决闪烁问题一直是动画制作的关键技术,因为没有人会愿意观看刺眼的一闪一闪的画面。<br>
既然想要解决这一问题,那就先要找到产生闪烁现象的原因在哪里。还记不记得动画过程是如何工作的:applet调用repaint( )方法通知系统进行重画,repaint(
)方法实际调用了update( )方法先清洗整个applet区域,然后再调用paint( )方法绘制屏幕。<br>
很明显,问题就出在update( )方法里,它每次清除屏幕,使画面每次都从有内容,到全空白,再画上内容,无疑造成了闪烁。下面就是update( )方法的缺省代码:<br>
public void update(Graphics g){<br>
g.setColor(getBackground()); //将背景色置为当前绘图颜色<br>
g.fillRect(0,0,width,height); //用背景色填充整个applet区域<br>
g.setColor(getForeground()); //将当前绘图颜色设回前景色<br>
paint(g); //进行重画<br>
}<br>
其中width和height是指整个applet的高度和宽度。很显然,我们必须覆盖这一方法,去改变它每次都呆板的用背景色去填充一下整个applet区域。那我们是否真的每次都需清除屏幕吗?回想一下,我们的applet每一次重画的内容都比前一次多一个字符。所以,如果前一个画面不清除,后一个画面叠加上去并不会破坏整个画面的内容,只有在全部字符都显示完全,才需要真正的清洗一下屏幕。因此,只在真正需要清除屏幕的时候才去做清除的动作,这应该说是消除闪烁的一个原则。下面,就是我们覆盖缺省的update(
)方法后的新代码:<br>
public void update(Graphics g){<br>
if (x_character= =0){<br>
g.setColor(getBackground());<br>
g.fillRect(0,0,appletWidth,appletHeight);<br>
g.setColor(getForeground());<br>
}<br>
paint(g);<br>
}<br>
另外有一点要改进的就是,为了能增加applet的灵活性和实用性,我们要尽量从HTML文件给applet传递各种配置参数,如要显示的字符串、字体、颜色、尺寸等信息,这样就不必每次小的改动都需要重新编译applet源代码。<br>
下面就是本实例经改进后的程序代码:<br>
import java.awt.Color;<br>
import java.awt.Font;<br>
import java.awt.FontMetrics;<br>
import java.awt.Graphics;<br>
public class RollingMessage extends java.applet.Applet implements Runnable {<br>
Thread runThread;<br>
String s; // 要显示的字符串<br>
int s_length; // 字符串的长度<br>
int x_character=0, // 当前显示到第几个字符串<br>
y_coord, // 字符串的Y坐标位置<br>
textcolor, // 字符串的颜色值(16进制整数rrggbb)<br>
backcolor, // applet背景颜色值(16进制整数rrggbb)<br>
delay; //每帧画面的时延(毫秒)<br>
int appletWidth, appletHeight;<br>
String font_name; // 字体的名称<br>
int font_size; // 字体的尺寸<br>
Font wordFont;<br>
FontMetrics wordMetrics;<br>
public void init() {<br>
String temp;<br>
appletWidth = size().width;<br>
appletHeight = size().height;<br>
temp=getParameter("font");<br>
font_name= (temp= =null) ? "TimesRoman" : temp;<br>
temp = getParameter("fontsize");<br>
font_size= (temp= =null) ? 12 : Integer.parseInt( temp ); //转换为10进制整数<br>
wordFont = new Font(font_name, Font.PLAIN, font_size);<br>
if (wordFont = = null)<br>
wordFont = getFont();<br>
wordMetrics = getFontMetrics (wordFont);<br>
temp = getParameter("text");<br>
s= (temp= =null) ? "Message goes here... " : temp;<br>
s_length=s.length();<br>
temp = getParameter("textcolor");<br>
textcolor= (temp= =null) ? 0 : Integer.parseInt( temp ,16 ); //转换为16进制整数<br>
temp = getParameter("backcolor");<br>
backcolor= (temp= =null) ? 0xffffff : Integer.parseInt( temp ,16 );<br>
temp = getParameter("delay");<br>
delay= (temp= =null) ? 100 : Integer.parseInt( temp );<br>
y_coord = appletHeight/2 + (wordMetrics.getHeight()-wordMetrics.getDescent())/2;<br>
}<br>
public void start() {<br>
if(runThread==null){<br>
runThread = new Thread(this);<br>
runThread.start();<br>
}<br>
}<br>
public void stop() {<br>
if(runThread!=null){<br>
runThread.stop();<br>
runThread=null;<br>
}<br>
}<br>
public void run() {<br>
while(true) {<br>
if (x_character++>s_length)<br>
x_character = 0;<br>
repaint ();<br>
try {<br>
Thread.sleep( delay );<br>
} catch (InterruptedException e) {}<br>
}<br>
}<br>
public void paint (Graphics g) {<br>
g.setFont (wordFont);<br>
g.setColor (Color.red);<br>
g.drawString (s.substring(0,x_character), 8, y_coord);<br>
}<br>
public void update(Graphics g){<br>
if (x_character = = 0){<br>
g.setColor(getBackground());<br>
g.fillRect(0,0,appletWidth,appletHeight);<br>
g.setColor(getForeground());<br>
}<br>
paint(g);<br>
}<br>
}<br>
下面是测试这一applet的HTML语言的例子:<br>
<applet code=RollingMessage.class width=400 height=60><br>
<param name=font value="TimesRoman"><br>
<param name=fontsize value=30><br>
<param name=text value="Welcome to here !"><br>
<param name=textcolor value="ff0000"><br>
<param name=backcolor value="ffffff"><br>
<param name=delay value=300><br>
<img src="java/rollingmessage.gif" WIDTH=251 HEIGHT=24 BORDER=0><br>
<h5>You need Java to use the RollingMessage applet!<br>
</applet></P>
<p> <a name="434"></a>4.3.4 放映图像</P>
<p> 有些人可能会觉得真正的动画应该是每一帧都有自己的图像,而不是仅仅跳出几个字符。那好吧,我们下面就来制作一个放映图像的动画例子,那就是一个会走的数码钟,其显示效果如图4-16所示。图像的动画例子,那就是一个会走的数码钟,其显示效果如图4-16所示。</P>
<p> <IMG
height=99 src="tu4-17.gif" width=130></P>
<p> 图4-16 会走的数码钟在放映图像前我们自然应该先准备好各个图像文件,本例的applet所需要的图像清单是:'0'到'9'共十幅数码管图像(文件名为lcd0.gif、lcd1.gif、...、lcd9.gif),一个冒号图像(colon.gif文件),一个钟的边框(frame.gif文件)。这些清单如图4-17所示。<IMG
height=106 src="tu4-18.gif" width=326></P>
<p> 图4-17 数码钟所用的各图像文件<br>
然后我们把这些图像都放在本applet目录下的dcimages目录下,由于我们把数码管图像的文件名取得相似,因而可以创建一个Image数组digit_image作为实例变量,并在init()方法中通过一个循环,将这十幅图像装载进来,如:<br>
Image[] digit_image = new Image[10];<br>
public void init()<br>
{<br>
for (int i = 0; i < 10; i++)<br>
{<br>
digit_image[i] = getImage(getCodeBase(), "dcimages/lcd" + i + ".gif");<br>
. . .<br>
}<br>
同样,用getImage( )方法装载其它两幅图像。下一步的工作就是要确定数码钟里每幅图显示的起始位置,这里主要是指X方向的坐标值(因为Y方向的坐标值是一样的)。<br>
我们把这些信息存放在一个整型数组(image_start_x)中,其中每个值的含义依次表示下列位置:小时数的十位数码、小时数的个位数码、第一个冒号、分钟数的十位数码、分钟数的个位数码、第二个冒号、秒钟数的十位数码、秒钟数的个十位数码。然后同样采用多线程机制,在run(
)方法中控制定时,一秒钟重画一次。而在paint()方法中则先获取当前的时间,然后用drawImage( )方法在相应的位置画出边框、相应的六个数码管图像及两个冒号。<br>
接下来的问题就是如何得到当前的时间呢?这就要用到java.util程序包里的Data类(别忘了import它哟)。这个类的构造方法中有一种不带任何参数的调用格式,它就会创建一个表示当前日期和时间的对象,得到这一对象后就可以调用Data类中提供的getHours()方法、getMinutes(
)方法与getSeconds( )方法来获取当前时刻的小时数、分钟数和秒数。<br>
例如:<br>
Date now = new Date( );<br>
int hour = now.getHours( );<br>
int minute = now.getMinutes( );<br>
int second = now.getSeconds( );<br>
另外,我们为了将该applet的宽度和高度就设置为数码钟边框所围的区域,就调用了Applet类中的resize( )方法,该方法传递两个整型参数,分别将该applet重新设置为所指定的高度和宽度。调用这一方法将覆盖HTML文件中"applet"标记的width属性和height属性的值,这样就可以防止用户对这两个属性值的错误设置。<br>
最后,我们要注意的问题自然又是关于闪烁。由于我们每次都在一系列固定的位置上放置大小相同的图片,因而根本不需每次用背景色清除画面。所以update( )方法只要简单地调用paint(
)方法就可以了:<br>
public void update(Graphics g)<br>
{<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -