优化Java动画编程中的显示效果

优化Java动画编程中的显示效果,第1张

Java动画编程有多种实现方法 但它们实现的基本原理是一样的 即在屏幕上画出一系列的帧来造成运动的感觉 Java多线程技术是Java动画编程中普遍运用的技术 它在控制动画程序的流程和动画的显示效果方面起着重要的作用 Java动画编程中的动画闪烁和图像残缺不全等现象 是Java程序员经常遇到的问题 本文以作者应用实例程序为基础 阐述如何运用多线程 重载Update 双缓冲和图像跟踪等技巧来解决这类问题 以达到动画显示的最佳效果 Java多线程技术Java多线程技术简介 目前 线程(Thread)已经为许多 *** 作系统和应用开发系统所采用 线程是程序的单个控制流 具有顺序程序的特点 但是 线程不是一个程序 它仅仅是程序的一个执行序列 线程具有很强的并发功能 在同一时刻可以有多个线程同时处于执行状态 线程是动态的 具有一定的生命周期 分别经历从创建 执行 阻塞 直到消亡的过程 Java语言对多线程编程的支持有两种实现方法 一种是直接继承Thread类 另一种是实现Runnable接口 Thread类提供了对线程的控制方法 如start() stop() run() suspend() resume()和sleep()等方法 它们可以对线程的状态进行控制 动画线程的设计与实现 为了每秒中多次更新屏幕 必须创建一个线程来实现动画的循环 这个循环要跟踪当前帧并响应周期性的屏幕更新要求 许多Java初学者容易犯的一个错误是将动画循环放在paint()中 这样占据了主AWT线程 而主线程将负责所有的绘图和事件处理 因此 应该生成一个独立的动画线程来完成图像的显示和更新 例如 在一个Applet框架下 当Applet启动(Start)时 生成一个动画线程在Applet停止(stop)时 终止该动画线程以释放它所占用的CPU资源 下列程序代码(简称 C 代码)是该动画线程的具体实现 public void start() { if(animatorThread==null) { animatorThread=new Thread(this)//开始动画线程animatorThread start()}}public void stop(){ //停止动画线程 animatorThread=null} 上面终止动画线程的时候 并不是调用该动画线程的stop()方法 而是设置该动画线程为null 因为如果直接调用线程的stop()方法会强制线程终止所有的执行工作 有时会带来不好的结果 设置该动画线程为null 则在run()方法中 由于不满足循环条件 线程会自然退出 这样 也进一步优化了该动画程序 重载update()和双缓冲技术消除闪烁在Java中 动画发生闪烁有两个原因 一个是由于在显示下一帧画面的时候 调用了repaint()方法 而repaint()方法被调用时 要清除整个背景 然后才调用paint()方法显示画面 这样 在清除背景和绘制图像的短暂时间间隔内被用户看见的就是闪烁 另一个是由于paint()方法要进行复杂的计算 绘制每一帧花费的时间太长 图像中的各个像素值不能同时得到 使得动画的生成频率低于显示器的刷新频率 从而造成闪烁 下面两种方法可以明显地消除或减弱闪烁 重载update()方法 当AWT接收到一个Applet的重绘请求时 它就调用Applet的update()方法 缺省情况下 update()方法清除Applet的背景 然后调用paint()方法 重载update()方法就可以将以前在paint()方法中的绘图代码包含在update()方法中 从而避免每次重绘时将整个区域清除 既然背景不再自动清除 Java程序员需要自己在update()中完成 双缓冲技术 另一种消除帧之间闪烁的方法是使用双缓冲技术 它在许多动画Applet中被使用 主要原理是创建一幅后台图像 将每一帧画入图像 然后调用drawImage()方法将整个后台图像一次画到屏幕上去 这种方法的优点在于大部分绘制是离屏的 将离屏图像一次绘至屏幕上 比直接在屏幕上绘制要有效得多 在创建后台图像前 首先要通过调用createImage()方法生成合适的后台缓冲区 然后获得在缓冲区做图的环境(即Graphics类对象) 下列实例程序代码(简称 C 代码)就是这两种方法的结合使用 双缓冲技术在重载update()方法中实现 其中 offImage是Image类的对象 offGraphics是Graphics类的对象 这两个类对象是实现双缓冲技术的关键 相关代码如下 public void paint(Graphics g){ update(g)} public void update(Graphics g){ Dimension d=getSize()//如果后台图像不存在 就创建一个后台图像if((offGraphics==null)||(d width!=offDimension width) ||(d height!=offDimension height)) { offDimension=doffImage=createImage(d width d height)offGraphics=offImage getGraphics()} //擦除上一帧 offGraphics setColor(getBackground())offGraphics fillRect( d width d height)offGraphics setColor(Color black)//将当前的帧输出到指定的image中 for(int i= i<10 i++){ offGraphics.drawImage(images[i],frameNumber*5%(d.width/2) ,i*d.height/10,this)} //输出指定的后台图像g.drawImage(offImage,frameNumber*5%(d.width/2),0,this)} 双缓冲技术可以使动画平滑,但有一个缺点,要分配一个后台图像的缓冲,如果图像相当大,这将占用很大一块内存。wINgWIt. 图像跟踪与程序的逐步完善图像跟踪 当动画线程刚刚启动的时候,由于没有全部载入图像,屏幕上显示的画面经常是残缺不全的。这时可以使用MediaTracker或ImageOberver类对象进行图像跟踪,待图像全部载入后,再调用drawImage()方法将图像输出到屏幕上去。DrawImage()方法的第四个参数正是ImageObserver类对象,所以可以用ImageObserver类对象进行图像跟踪。在实际应用Applet程序的init()方法中实现图像跟踪,相当于在动画线程的DrawImage()方法调用以前就画了一次图像,因为动画线程的初始化过程,即init()方法是先被调用的。下列代码(简称“C3”代码)展示了init()方法使用MediaTracker类对象来实现跟踪图像的载入,代码如下: public void init(){ tracker=new MidiaTracker(this)for(int i=1i<=10i++){ image[i-1]=getImage(getCodeBase(),"image"+i+" .gif"); //用MediaTracker类对象的addImage()方法跟踪图像的载入 tracker.addImage(images[i-1],0)}......}程序的进一步完善 在“C2”代码的重载update()方法中加入下列if语句,从而对MediaTracker类对象的图像跟踪方法做出判断,if语句如下: if(!tracker.checkAll()){ //如果图像还没有装载完毕,则仅清除背景,同时输出一个状态 g.clearRect(0,0,d.width,d.height)g.drawString("Please wait...",0,d.height/2)return}在“C1”代码的stop()方法中加入两行代码,用以释放由双缓冲技术所占用的内存资源,这时stop()方法改为: public void stop(){ //停止动画线程 animatorThread=null//释放用于双缓冲的内存资源 offGraphics=nulloffImage=null} 程序修改到此,还有一个小问题,就是动画线程启动后,第一幅图像有时仍有残留痕迹,而不是随着图像的更新而完全擦除掉。如果想解决此问题,只要将“C2”代码中最后的for()循环和g.drawImage()方法改为如下代码就可以了。 for(int i=0i<10i++){ offGraphics.drawImage(images[frameNumber%10], ,frameNumber*5%(d.width),i*d.height/10,this)}g.drawImage(offImage,0,0,this)保持恒定的帧速度为了使用户观看动画时没有闪烁感,至少需要达到每秒12帧的速度。更高的帧速度会产生更平滑的动画。通常,在动画显示的每两帧之间,调用线程的sleep()方法休眠一个固定的时间。这样做的缺点是使用绝对的延迟时间会使延迟过长,即造成等待时间过长。为了每秒显示10~20帧图像,并保持恒定的帧速度(也就是恒定的显示频率),在动画线程的run()方法中可加入如下代码: try{ startTime+=delayThread.sleep(Math.max(0,startTime-System.currentTimeMillis()))}catch(InterruptedException e){ break} 本文着重阐述了优化Java动画编程的显示效果的几种方法。当然,随着Java技术以及其它计算机技术的发展,还将会有多种优化动画显示效果的方法,例如,在提高动画的帧速度方面,可在Java中调用微软公司的DirectDraw工具。但是本文所介绍的方法更具有通用性。 lishixinzhi/Article/program/Java/JSP/201311/19234

一: 用多线程播放一组图片, 实现动画片的效果类似于逐帧动画,每个图片是动画的一帧

二: 在awt/swing界面里, 可以使用paint方法,去绘制图形,然后用swing提供的Timer或者多线程技术,去刷新绘制的图形

三:在JavaFX里, 本身就支持动画,并且封装了很多动画效果可以直接使用,比如逐帧动画.缩放动画,渐变动画,旋转动画,位置动画等.

强烈推荐使用javaFX来实现动画, 因为javaFX是现代化的图形界面工具,具有简单,强大,组件丰富,跨平台,支持Html5, 支持表格, 支持动画等多种优势 

下面是一个javaFX绘制的动态表格

javaFX动态表格

效果图

参考代码

import java.awt.*

import java.awt.event.*

import javax.swing.*

public class MoveTextFrame extends JFrame {

JLabel jl//文字标签

int speed=2//移动速度

public MoveTextFrame() {

jl = new JLabel("文字动画")

jl.setForeground(Color.RED)

add(jl)

setSize(380, 100)//窗口大小

setLocationRelativeTo(null)//窗口居中

setResizable(false)

setDefaultCloseOperation(EXIT_ON_CLOSE)

setVisible(true)

//设置定时器, 每隔25毫秒,改变一次文字标签的位置

Timer t = new Timer(25, new ActionListener() {

public void actionPerformed(ActionEvent e) {

int x = jl.getX()+speed//计算移动后的位置

if(x>=390){//如果超过就指定像素,就重新从左边开水移动

x=-30

}

jl.setLocation(x, jl.getY())//更新位置

//repaint()

}

})

t.start()

}

public static void main(String[] args) {

new MoveTextFrame()

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12133712.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存