2008年(3500)
分类:
2008-05-04 19:14:14
Java 世界 里 最 激 动 人 心 的 时 刻 终 于 到 来 了 , 在 这 一 章 里 你 将 学到 在 主 页 里 播 放 动 画 的 技 巧 , 以 及 载 入 和 播 放 声 音 的 方法 , 掌 握 了 本 章 所 讲 授 的 这 些 技 巧 , 再 加 上 你 脑 子 里 各种 希 奇 古 怪 的 念 头 , 你 就 有 能 力 创 造 出 你 自 己 的 真 正 活灵 活 现 、 有 声 有 色 的 活 动 Web 主 页 来 。
孙 悟 空 的 筋 斗 是 怎 么 翻出 来 的 ?
我 们 知 道 电 影 是 一 张 张 电 影 胶 片 在 放映 机 前 滚 过 , 在 银 幕 上 投 影 出 动 态 的 画 面 , 动 画 片 是 由一 组 差 异 很 小 的 图 片 组 合 在 一 起 , 快 速 地 切 换 这 些 图 片, 你 所 看 到 的 就 是 一 个 在 翻 跟 头 的 孙 悟 空 。 那 么 计 算 机上 的 动 画 也 是 这 样 做 出 来 的 吗 ? 基 本 原 理 差 不 多 。 首 先要 有 一 组 连 续 动 作 的 图 片 , 然 后 只 需 要 快 速 地 用 这 一 组图 片 顺 序 刷 新 显 示 器 上 的 画 面 就 可 以 看 到 一 张 张 静 态 的画 面 变 成 一 段 可 爱 的 动 画 片 段 了 。
所 以 用 Java 来 实 现 动 画 实 在 是 再 简 单 不过 了 , 你 肯 定 马 上 就 想 到 了 前 面 已 经 学 过 的 加 载 和 显 示图 片 。 既 然 制 作 动 画 最 基 本 的 两 个 步 骤 你 都 会 了 , 那 还有 什 么 能 难 得 住 你 呢 ? 现 在 你 已 经 会 用 getImage 把 一 个 图形 文 件 加 载 到 Java 程 序 中 , 并 用 drawImage 把 加 载 进 来 的 图片 输 出 到 你 的 Applet 窗 口 中 。 ( 如 果 getImage 和 drawImage 这两 个 方 法 你 忘 了 的 话 , 请 参 阅 第 十 二 章 。 ) 问 题 是 在 这一 章 中 我 们 将 加 载 的 不 是 单 张 的 图 片 , 而 是 一 组 图 片 ,并 依 次 每 隔 一 段 时 间 就 显 示 一 张 。 我 们 怎 么 控 制 它 什 么时 候 该 换 掉 旧 的 显 示 新 的 呢 ? 问 得 好 ! 这 就 是 下 面 要 讲的 问 题 。
动 画 效 果 的 好 坏 不 仅 仅 取 决 于 画 面 是否 漂 亮 , 而 且 还 取 决 于 动 画 中 动 作 的 平 滑 程 度 。 我 们 当然 不 希 望 看 到 自 己 主 页 里 的 动 画 动 起 来 像 僵 硬 的 木 偶 ,要 让 你 的 动 画 看 上 去 动 作 连 贯 平 滑 就 需 要 控 制 切 换 图 片的 速 度 。 可 想 而 知 , 相 同 时 间 内 放 映 的 图 片 张 数 越 多 ,动 画 中 人 物 的 动 作 看 上 去 就 越 平 滑 。
那 么 Java 到 底 靠 什 么 来 决 定 何 时 显 示 图片 、 何 时 更
换 图 片 呢 ? 当 然 是 时 钟 。 每 台 计 算 机 内 部 都有 一 个 很 精 确 的 时 钟 , 计 算 机 依
赖 它 才 能 有 条 不 紊 地 进行 工 作 。 我 们 可 以 对 显 示 的 每 一 帧 图 片 计 时 , 一 到 规
定时 间 就 把 它 撤 换 掉 , 定 时 地 顺 序 地 替 换 组 成 动 画 的 每 一帧 画 面 , 画 不 就 动
起 来 了 吗 ? 那 我 们 用 什 么 来 计 时 呢 ?线 程 ! 这 是 最 好 的 解 决 办 法 。 支 持 多 线
程 也 是 Java 的 一大 特 征 。
什 么 是 线 程 ?
" 线 程 ” 这 个 词 似 乎 听 说 过 。 其 实 它 的确 也 没
有 什 么 神 秘 的 , 线 程 就 是 执 行 中 的 一 段 程 序 。 举个 生 活 中 的 例 子 : 生 活 中 很
多 事 情 都 可 以 看 作 是 线 程 ,比 如 吃 饭 、 睡 觉 、 看 书 、 工 作 … … 有 时 候 为 了 提
高 效 率, 你 可 能 会 同 时 做 几 件 事 , 每 一 件 事 叫 做 一 个 线 程 , 那么 你 就 工 作 在
多 线 程 状 态 下 了 。 假 设 你 正 在 准 备 晚 餐 ,微 波 炉 里 正 烤 着 面 包 , 咖 啡 壶 里 正
煮 着 咖 啡 , 你 也 许 正在 煤 气 灶 边 忙 着 煎 鸡 蛋 。 你 得 不 时 地 关 照 着 微 波 炉 和 咖啡
壶 , 还 得 注 意 不 要 把 蛋 煎 糊 了 , 如 果 电 话 铃 响 了 , 你还 得 把 电 话 夹 在 腋 窝 下
接 电 话 。 那 我 要 说 你 简 直 是 个 效率 专 家 , 你 正 在 完 成 多 线 程 任 务 。
图 18.1 什 么 是 多 线 程
其 实 Java 就 是 一 种 能 让 CPU 忙 得 团 团 转的 语 言 , 因 为 它 支 持 多 线 程 。 它 可 以 让 CPU 同 时 从 从 网 络上 读 取 数 据 、 等 待 用 户 的 输 入 、 在 屏 幕 上 显 示 动 画 , 并且 向 打 印 机 发 出 打 印 指 令 。 你 看 Java 通 过 它 的 多 线 程 机制 大 大 地 提 高 了 CPU 的 工 作 效 率 。
既 然 多 线 程 是 这 么 一 个 好 东 西 , 我 们何 不 利 用 它 呢
。 听 起 来 似 乎 挺 复 杂 , 其 实 使 用 多 线 程 的过 程 很 简 单 。 只 要 遵 循 固 定 的 步 骤
, 一 步 步 地 在 程 序 里加 入 我 们 想 做 的 事 情 就 可 以 了 。 1.用 你 所 编 的 Applet
去 实 现 Runnable 接 口 。
2.在 方 法 start 中 产 生 一 个 新 的 工 作 进程 。
3.在 方 法 stop 中 编 写 结 束 线 程 要 处 理 的事 情 。
4.加 一 个 run 方 法 , 在 这 个 方 法 中 写 你想 让 新 产 生 的
那 个 线 程 做 的 事 情 , 其 实 就 是 给 新 线 程 分配 任 务 。
哦 ! 我 又 糊 涂 了 , 又 是 线 程 , 又 是 方法 , 还 有 什 么 接 口 。 我 们 下 面 就 一 步 一 步 地 讲 。
第 一 步 : 让 你 的 Applet 实 现 Runnable 接 口 。
这 并 不 难 理 解 , 我 们 可 以 把 每 个 程 序看 作 一 个 线 程
, 它 从 开 始 到 结 束 只 能 干 一 件 事 。 如 果 你想 让 它 同 时 干 两 件 事 , 就 必 须 在 原
来 那 个 程 序 里 加 上 Runnable 接 口 以 便 让 连 贯 线 程 能 够 同 时 工 作 。 举 个 例 子
来 说 , 一个 电 源 插 座 上 只 能 插 一 个 电 器 , 如 果 你 正 在 看 电 视 , 就不 能 使 用 录
像 机 , 可 是 你 想 把 好 看 的 节 目 录 下 来 , 非 用录 像 机 不 可 , 怎 么 办 呢 ? 聪 明 的
你 马 上 就 想 到 加 一 个 插线 板 问 题 就 解 决 了 。 在 这 里 Runnable 接 口 就 是 线 程
的 插 线板 , 只 要 你 的 Applet 实 现 了 Runnable 接 口 , 它 就 可 以 成 为 多线 程 程
序 了 , 而 且 实 现 Runnable 接 口 也 的 确 和 加 一 个 插 线板 一 样 简 单 , 你 只 需 要
这 样 写 : public class cartoon extends java.applet.Applet implements
Runnable { … … }
这 句 话 的 前 面 一 部 分 , 我 们 都 已 经 很 熟 悉了 , cartoon 是
你 的 Applet 的 名 字 , implements Runnable 就 是 咱们 的 插 线 板 。
第 二 步 : 在 Start 方 法 里 产 生 一 个 新 的 线 程。
在 Java 里 线 程 也 被 当 作 一 个 类 。 类 Thread 封 装 了
所 有 有 关 线 程 的 控 制 , 用 来 控 制 线 程 的 运 行 、 睡眠 、 挂 起 和 中 止 。 Thread
类 是 唯 一 可 以 用 来 控 制 线 程 的 手段 。 start 的 实 现 很 简 单 。
public void start ( )
{ if (thread1 == null )
{ thread1 = new Thread ( this ) ;
thread1. start ( ) ;
}
}
方 法 start 里 产 生 了 一 个 新 的 进 程 , 当 start( ) 执 行 完
以 后 , 程 序 里 就 有 了 两 个 线 程 在 同 时 工 作 , 一个 是 原 来 的 程 序 , 另 一 个 则 是
由 start( ) 产 生 的 , start( ) 中 产 生 的 这 个 线 程 完 成 下 面 将 谈 到 的 方 法
run 中 指 定 的 任务 。
第 三步 : 在 方 法 stop( ) 里 把 start( ) 产 生 的 一 个 线 程 关 掉 , 中止 线 程 的
工 作 , 并 释 放 线 程 , 用 stop 中 止 的 线 程 将 不 能再 启 动 , 也 就 是 说 这 个 线 程
已 经 死 了 , 所 以 应 该 释 放 它。 Stop 方 法 应 该 这 样 写 :
public void stop ( )
{ thread1.stop ( ) ;
thread1 = null ; }
第 四 步 : 在 run( ) 方 法 里 给 新 产 生 的 进 程 分配 任 务 。
run 是 线 程 的 核 心 , 在 这 个 方 法 里 , 我们 将 写 入 新 线 程 工 作 的 程 序 代 码 , 告 诉 这 位 新 来 的 线 程先 生 该 做 什 么 。 事 实 上 你 可 以 在 方 法 run 里 做 任 何 你 想 做的 事 情 , 原 来 的 那 个 线 程 并 不 会 因 为 它 而 受 到 什 么 影 响, 因 为 它 们 是 两 个 完 全 独 立 的 线 程 , 互 不 干 扰 。 这 里 还要 提 一 句 , 除 了 stop 可 以 中 止 线 程 的 工 作 外 , run 中 的 程序 代 码 一 旦 执 行 结 束 , 线 程 也 会 自 动 中 止 。
好 啦 ! 讲 了 这 么 多 , 不 知 道 你 清 楚 了没 有 ? 如 果 你 还 是 觉 得 云 山 雾 罩
, 没 有 关 系 , 只 要 你 照着 这 四 个 步 骤 一 步 步 来 , 你 仍 然 能 很 容 易 写 出 一 个 像
模像 样 的 多 线 程 程 序 来 。 下 面 就 让 我 们 来 试 试 吧 。
翻 筋 斗 的 小 企 鹅
这 一 章 不 是 讲 动 画 吗 ? 怎 么 又 讲 这 么一 大 堆 线 程 的
东 西 ? 这 是 因 为 要 编 出 一 个 好 的 具 有 动 画效 果 的 Java 程 序 , 就 必 须 利 用 线
程 。 所 以 前 面 我 们 是 在为 这 一 节 打 基 础 , 现 在 我 们 已 经 知 道 怎 样 启 动 和 中 止
一个 线 程 , 怎 样 在 方 法 run 中 指 定 线 程 工 作 。 那 么 就 把 它 用到 咱 们 的 动 画 程
序 里 来 吧 !
程 序 18.1 // animate.java
import java.awt.*;
public class animate extends java.applet.Applet
implements Runnable // 实 现 Runnable 接 口
{
Image frame[ ]; // 说 明 一 个 Image
数 组 , 准 备 放 动 画 图 片
Thread thd; // 说 明 一 个 Thread ( 线
程 ) 对 象
int num; // 设 置 计 算 帧 数的 计 数 器
int pause; // 设 置 每 帧 显 示的 时 间
public void init( )
{
String fps; // 设 置 每秒 切 换 图 片
的 张 数
frame = new Image[17]; // 构 造 Image 数
组 , 共 包 含 17 个 元 素
thd = null; // 初始 化 线 程
num = 0; // 计 数 器 置 0
for (int i = 0; i < frame.length; i )
// 加 载 图 片
frame[i] = getImage(getCodeBase( ), "images/T"
i ".gif");
fps = getParameter("speed");
// 从 HTML 文 件 读 入 参 数 speed , 确 定 放 映 速 度
if (fps == null) // 如 果 HTML 中 未指 定 参
数 , 则 用 省 缺 的 放 映 速 度
fps = "10"; // 为 每
秒 10 帧
pause = 1000 / Integer.parseInt(fps);
// 计 算 每 帧 图 片 显 示 的 时 间
}
public void start( )
{
if (thd == null)
{
thd = new Thread(this); // 在 start(
) 方 法 里 产 生 一 个 新 线 程 , 名 为 thd
thd.start( ); // 启 动 这个 新 线 程
}
}
public void stop( )
{
if (thd != null)
{
thd.stop( ); // 在 stop( ) 方 法
里 中 止 线 程 thd
thd = null; // 释 放 线程
}
}
public void run( )
{ while (true)
{ try { Thread.sleep(pause); } // 让线
程 睡 眠 每 一 帧 图 片 的 显 示 的 时 间
catch (InterruptedException e) {}
repaint( ); // 重 画 窗口
num = (num 1) % frame.length; // 计数
器 增 1
}
}
public void paint(Graphics g)
{
g.drawImage(frame[num], 0, 0, this);
// 显 示 计 数 器 指 定 的 那 帧 图 片
}
public void update(Graphics g)
{
paint(g);
}
}
该 程 序 的 HTML 文 件 如 下 所 示 :
< HTML>
< HEAD>
< TITLE>animate< /TITLE>
< /HEAD>
< BODY>
< APPLET CODE = "animate.class" WIDTH
= 130 HEIGHT = 80>
< param name = "speed" value = "5">
< /APPLET>
< /BODY>
< /HTML>
下载本文示例代码
第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)第十八讲 动画制作及声音载入(一)