网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  事件监听器?将javabeans接通起来的方法     
  文章作者:未知  文章来源:水木森林  
  查看:63次  录入:管理员--2007-11-17  
 
  摘 要 javabeans 通 过 事 件( 封 装 着 与 所 发 生 情 况 有 关 的 数 据 的 对 象) 与 其 它 软 件 组 件 进 行 通 讯。 本 文 将 向 你 展 示 如 何 利 用java 的 新 的 事 件 框 架 把beans 接 通 起 来, 以 生 成 新 的beans 或 构 造 完 整 的 应 用 程 序。 在 阐 述 这 个 问 题 的 过 程 中, 我 们 将 会 涉 及 到 一 些java 语 言 的 新 特 性。

通 过 适 当 配 置,javabeans 能 够 去" 监 听" 其 它 软 件 对 象。 而 且 正 如 你 将 要 看 到 的 一 样, 一 个java1。1 类( 包 括 任 何 一 个javabeans) 一 旦 成 为 一 个 事 件 监 听 者, 就 不 仅 仅 只 能 够 监 听 其 父 类, 而 且 能 够 监 听 所 有 产 生 事 件 的 类。 事 件 监 听 者 的 思 想 正 是java 类( 和 其 它javabeans) 如 何 处 理 事 件 的 关 键。

我 先 来 介 绍 两 个 图 标, 它 们 将 帮 助 我 们 识 别 一 些 关 键 问 题。

javabeans 是 一 个 重 要 概 念

cuppajoe 图 标 表 示 对 于java 语 言 来 说 新 的 或 重 要 的 思 想

什 么 是 事 件
软 件 事 件 是 一 段 说 明 某 事 已 经 发 生 的 数 据。 用 户 移 动 鼠 标, 或 从 网 上 传 来 数 据 报, 或 传 感 器 监 测 到 某 人 非 正 常 介 入, 所 有 这 些 发 生 的 情 况, 都 可 以 被 看 成 是 事 件 的 实 例, 而 有 关 这 些 情 况 的 信 息 可 以 包 括 在 事 件 之 中。 通 常 情 况 下, 根 据 事 件 处 理 来 开 发 软 件 系 统 是 较 为 方 便 的: 在 此 情 况 下, 程 序 设 计 变 成 一 种 对" 当 此 发 生 时, 做 彼" 式 的 叙 述 进 行 加 工 处 理 的 过 程。 如 果 鼠 标 已 被 移 动, 则 随 之 移 动 屏 幕 上 的 光 标; 如 果 网 上 传 来 数 据 报, 则 读 之; 如 果 发 现 有 人 侵 入, 则 驱 逐 之。

通 常 而 言, 一 个 事 件 包 括 以 下 信 息: 事 件 源( 产 生 事 件 或 最 初 接 收 到 事 件 的 对 象), 事 件 的 发 生 时 刻, 和 一 些 事 件 接 收 者 可 能 用 到 的 说 明 什 么 情 况 发 生, 如 何 去 做 的 子 类 的 具 体 信 息。 例 如, 在windows 系 统 中, 就 应 当 有 一 个 关 于 点 击 鼠 标 的 事 件 子 类。 点 击 鼠 标 事 件 将 包 括 点 击 鼠 标 时 的 时 刻; 也 可 能 包 括 当 点 击 发 生 时, 鼠 标 在 屏 幕 上 的 位 置,shift 键 和alt 键 的 状 态, 是 点 击 了 鼠 标 左 键 还 是 右 键 等 等 诸 如 此 类 的 信 息。 处 理 事 件 的 编 码, 不 可 思 议 地 被 称 为" 事 件 处 理 者"(event handler)。

那 么, 所 有 这 些 与javabeans 有 何 关 系 呢? 事 件 是beans 相 互 通 讯 的 主 要 方 式。 这 点 我 们 在 下 面 将 会 看 到。 如 果 你 正 确 地 选 择 了 事 件 和 它 们 的 连 接, 你 就 可 能 在 你 的 应 用 系 统 中 将beans 相 互 接 通, 让 每 一 个beans 按 照 你 的 意 愿 去 响 应 与 其 相 关 的 事 件。 每 一 个beans 将 各 负 其 责, 对 新 来 的 事 件 进 行 适 当 地 响 应, 并 且 当 新 的 情 况 出 现 的 时 候, 向 相 关 的 邻 居beans 发 送 新 的 事 件。 一 旦 你 知 道 如 何 利 用 事 件, 你 就 能 够 写 出 通 过 事 件 和 其 他 组 件 进 行 通 讯 的beans。 更 进 一 步 地 讲, 外 部 系 统, 例 如 集 成 开 发 环 境(ides) 能 够 自 动 地 检 测 你 的beans 所 用 的 事 件, 并 能 让 你 以 图 解 的 方 式 来 互 连beans。ides 同 样 也 能 向javabeans 发 送 事 件 和 从javabeans 接 收 事 件, 本 质 上 讲, 可 以 从 外 部 来 控 制javabeans。

为 了 了 解 事 件 怎 样 和beans 一 起 工 作, 你 就 必 须 了 解 他 们 在java 中 是 如 何 工 作 的。 而 事 件 工 作 的 方 式 各 不 相 同,jdk1。1 则 是 标 准 的。

jdk 1。0 的 事 件 机 制 有 何 问 题?
在jdk1。0 中, 事 件 主 要 被 用 在 抽 象 视 窗 工 具 包(awt) 中, 当 在 用 户 接 口 上 出 现 某 种 情 况 时, 它 将 通 知 相 应 的 类。 程 序 员 应 用 继 承 机 制, 通 过 创 建 某 个 类 的 能 够 接 收 相 应 的 事 件 类 型 的 子 类 对 象 和 重 载 父 类 的 事 件 处 理 过 程, 来 进 行 事 件 处 理。

例 如, 在java1.0 版 中, 能 够 获 得 某 个 行 为 事 件(action event) 的 唯 一 途 径, 就 是 把 它 从 某 个 知 道 如 何 处 理 此 行 为 事 件 的 类 中 继 承 下 来。

public class mybutton extends java.awt.button
{
//重载action()方法以处理行为事件
public boolean action(event evt, object what)
{
//此处,做一些行为事件所做的事
}
}

这 意 味 着, 只 有 从java。awt。button 中 继 承 下 来 的 类 才 能 够 响 应 点 击 鼠 标 事 件。 这 种 组 织 结 构 与 用 户 接 口 捆 绑 在 一 起, 不 够 灵 活 方 便。 它 不 便 于 构 造 新 的 事 件 类 型。 而 且 即 便 你 能 够 构 造 新 的 事 件, 你 也 很 难 改 变 那 些 将 被 类 响 应 的 事 件, 因 为 有 关 的 信 息 都 被 僵 硬 地 固 化 在awt 的" 族 系 树"( 继 承 图) 中。

新 的jdk1。1 拥 有 一 个 更 为 普 适 的 事 件 框 架, 它 能 够 让 产 生 事 件 的 类 和 其 它 不 产 生 事 件 的 类 互 相 通 讯。 新 的 模 式 放 弃 了 定 义 客 户 子 类 必 须 重 载 的 事 件 处 理 函 数( 方 法) 的 工 作 方 式, 转 而 采 用 定 义 接 口 的 方 式。 如 果 一 个 类 需 要 接 收 某 一 特 定 的 消 息 类 型, 则 这 个 类 可 以 使 用 所 定 义 的 接 口。( 你 可 能 会 明 白, 这 意 味 着 通 过" 授 权"(delegation), 而 不 是 通 过" 继 承"(inheritance) 来 处 理 事 件)。 我 们 将 还 以jdk1。0 button 例 子 来 说 明jdk1。1 的 模 式。

我 在 此 想 要 做 的 事 是, 构 造 一 个 新 的 类, 使 它 能 够 在 按 钮 被 按 下 时, 去 做 某 件 事 情。 在jdk1。0 版 中, 为 了 处 理 与 按 钮(button) 行 为 相 关 的 事 件, 我 必 须 继 承java。awt。button, 这 样, 一 旦 某 个 按 钮 被 按 下 时, 该 按 钮 将 会 让 我 的 新 类 知 道。

//...在程序的另一个地方,我们定义了"监听"按钮行为的对象
actionlistener myactionlistener = new actionlistener();
//...

//按钮行为事件
public class mybutton extends java.awt.button
{
//重载action()以通知我的新类
public boolean action(event evt, object object)
{
myactionlistener.action(evt, object);
}
}

现 在, 每 当mybutton 被 按 下 时,myactionlistener 对 象 都 会 收 到 一 个 事 件。myactionlistener 并 非 一 定 要 是java。awt。component 的 一 个 子 类, 但 它 的 确 要 包 括 一 个action() 方 法。 我 们 把 这 个 新 类 称 为actionlistener, 是 因 为 这 个 新 类 一 直 将 要" 监 听" 它 所 依 附 的botton 的 行 为 事 件。 在 此, 仍 有 一 些 问 题 存 在:

当 按 下 此 按 钮 时, 将 要 通 知 的 对 象 是 固 定 在 程 序 中 的, 这 就 是 说, 我 不 能 在 程 序 运 行 时 刻(runtime)" 重 新 接 通"button 和myactionlistener 的 关 系。

仅 有 一 个 对 象 可 被 通 知 到; 如 果 其 它 几 个 对 象 都 与 点 击button 有 关 系, 这 该 如 何 解 决?

我 们 仍 然 没 有 解 决 通 过" 继 承" 来 接 收 按 钮 行 为 事 件 的 难 题-- 这 就 是 说,myactionlistener 仍 必 须 从 某 个" 了 解" 按 钮 及 其 行 为 事 件 的 类 中 继 承 下 来。
对 第 一 个 问 题, 有 一 个 可 供 选 择 的 办 法 是 在mybotton 类 中 增 加setlistener(actionlistener newlistener) 及mynewclass getlistener() 两 个 方 法, 和 一 种 能 更 换 被 通 知 的 对 象 的 途 径。 然 而 非 常 不 幸, 我 们 仍 然 不 能 仅 仅 局 限 于 为 每 一 个 按 钮 关 连 一 个 对 象, 因 而 下 面 你 将 看 到, 我 们 将 生 成 一 系 列 的 监 听 器(listeners)。

//按钮行为事件( button action event)
public class mybutton extends java.awt.button
{
private vector listeningobjects = new vector();

//重载action()以通知我的新类
public boolean action(event evt, object object)
{
for (int i = 0; i

好 了 , 现 可 以 看 到 , 任 何 一 个actionlistener 的 实 例 都 可 以 通 过 调 用addactionlistener(this)" 监 听" 任 何 一 个mybutton 实 例 上 的 事 件 , 并 且 通 过 调 用removeactionlistener(this) 结 束" 监 听"。 这 一 进 步 的 确 不 错 , 但 是 有 关" 继 承" 的 问 题 仍 然 困 绕 着 我 们: 只 有button 和actionlistener 对 象( 及 其 派 生 类 对 象) 才 能 接 收 到button 行 为 事 件。 对 此 ,java 有 着 新 的 解 决 路 线: 接 口。

接 口 和 事 件 监 听 器
在java 术 语 表(http://java。sun。com/docs/glossary。html) 中 将 接 口 定 义 如 下:

接 口(interface): 在java 中 , 是 一 组 特 定 的 方 法 , 这 些 方 法 可 以 在 多 个 不 同 的 类 中 实 现 , 而 不 必 考 虑 这 些 类 在 类 系 结 构 中 的 等 级 关 系。

为 什 么 它 会 如 此 有 用?
接 口 定 度 了 一 “角 色”,通 过 实 现 这 一 接 口 中 的 一 系 列 操 作 , 每 一 个 类 都 可 以 扮 演 接 口 的 角 色 。

接 口 的 定 义 和 类 的 定 义 看 起 十 分 相 似:

// 仍 在jdk1.0 内
public interface actionlistener
{
void action(event evt, object object);
}

任 何 想 成 为actionlistener 的 类 只 要 简 单 地 定 义 一 个 行 为 函 数 , 并 且 通 过 应 用"implements" 关 键 词 , 声 明 它 实 现actionlistener 接 口:

public class somerandomclass extends someotherclass implements actionlistener
{
//实现actionlistener方法
void action(event evt, object object)
{
//做所要做的事
}

somerandomclass()
{
super();
// blah blah blah...
}
// ...继续实现somerandomclass方法
}

这 很 直 接, 拥 有 接 口, 你 将 不 会 再 被 禁 锢 于 森 严 的 单 一 继 承 阶 层 体 系 中 。

按 照 面 向 对 象 的 语 法, 继 承 常 常 被 称 为 一 种isa( 即is a) 关 系: 人 类 继 承 于 哺 乳 动 物, 因 为 人 是 一 种(is a) 哺 乳 动 物 。 对 象 通 过 参 照 索 引 或 指 针 建 立 起 来 的 联 系, 在 有 些 情 况 下 被 称 为hasa(has a, 有 一 个) 关 系: 如 一 辆 汽 车hasa 机 轴 。

接 口 结 构 给 面 向 对 象 的 思 想 注 入 了acts_as_a(act as a, 充 当 一 个) 的 概 念 。 在 上 面 的 例 子 中, 任 何 一 个 想 充 当(actasa)actionlistener 的 类 只 需 实 现 接 口 即 可 。

在 接 口 中 的 所 有 方 法 都 只 能 抽 象 地 定 义, 也 就 是 说, 在 接 口 中 不 应 有( 也 不 该 有) 实 际 的 方 法 代 码 。 因 此, 如 果 你 的 类 扩 充 了 一 个 接 口, 你 就 必 须 为 每 一 个 方 法 提 供 某 个 具 体 的 实 现 。

jdk1 。1awt 为 你 预 先 定 义 了 处 理 事 件 的 接 口, 并 且awt 用 户 接 口 元 件 提 供 了 上 面 所 说 的addeventtypelistener 和removeeventtypelistener 。 例 如, 在jdk1 。1 中, 在java 。awt 。button 就 有 以 下 两 个 方 法:

void addactionlistener(actionlistener listener)
void removeactionlistener(actionlistener listener)

这 就 意 味 任 何 一 个actionlistener 能 够 将 自 已 加 入 到 监 听action 事 件 的 对 象 列 表 中 。 一 个 类 通 过 实 现(implement)actionlistener 接 口 取 得actionlistener 的 资 格 。

public interface actionlistener extends eventlistener
{
public void actionperformed(actionevent e)
}

所 有 想 接 收 事 件 的 类, 至 此 不 必 从actionlistener 中 继 承 了 ? ? 它 们 仅 仅 只 需 实 现actionlistener, 并 对 某 些 对 象 充 当actionlistener 的 替 代 角 色, 即 能 够 去 接 收 事 件 。

actionperformed 方 法 的 参 数,actionevent, 是 一 个 源 于java 。util 。eventobject 的 类, 它 提 供 了 几 个 有 用 的 函 数, 来 帮 助 事 件 监 听 器 认 清 当 事 件 发 生 时, 是 谁 在 发 送 事 件,shift 和alt 键 处 于 什 么 状 态 等 等 之 类 的 情 况 。 读 者 可 以 从 联 机 文 件 中 查 看 这 些 事 件 的 全 部 功 能( 参 见 下 面 的" 资 源" 一 段) 。

同 时 也 应 当 注 意, 接 口 扩 充eventlistener, 而eventlistener 本 身 也 是 一 个 没 有 方 法 的 接 口, 需 要 事 件 监 听 器 去 扩 充 空 的java 。util 。eventlistener 接 口, 该 接 口 可 使 程 序( 特 别 是ides) 用 一 抽 象 的 方 法( 例 如 保 存 一 个eventlisteners 的 清 单) 去 操 纵 其 各 种 子 类 的eventlisteners 。

所 有 这 些 与beans 有 何 关 系?
javabeans主 要 利 用 事 件 监 听器 接 口 进 行 通 讯

事 件 监 听 器 为 对 象 提 供 了 一 种 普 适 的 不 经 过 继 承 关 系 而 进 行 通 讯 的 方 法 。 正 因 为 如 此, 他 们 对 于 组 件 技 术 来 说, 是 一 种 非 常 好 的 通 讯 机 制, 从 某 种 角 度 来 讲, 它 们 即 是javabeans 。 虽 然 上 面 看 到 的 事 件 监 听 器 全 都 出 现 在awt 中, 但 他 们 的 应 用 不 仅 仅 限 于 用 户 接 口 。 他 们 可 以 被 应 用 于 各 式 各 样 的 事 件: 属 性 的 变 更, 传 感 器 的 阅 读, 时 钟 事 件, 文 件 系 统 行 为, 对 象 命 名 等 。

现 在 开 始 “beany”部 分

# 你 能 够 为 它 们 定 义 你 自 己 的 事 件 类 型 和 事 件 监 听 器 。

# 如 果 你 的 新 事 件 类 型 被 称 为eventtype, 那 么 通 过 实 现 下 面 两 个 方 法, 你 的beans 就 能 成 为 你 的 新 事 件 类 型 的 源 。

o addeventtypelistener(eventobject e)
o removeeventtypelistener(eventobject e)

# 那 么 通 过 实 现 接 口eventlistener, 其 它beans 能 够 成 为 事 件 的 目 标 。

# 最 后, 你 可 以 通 过 调 用sourcebean 。addeventtypelistener(targetbean)" 接 通" 事 件 的 源 和 事 件 目 标 。

创 建 和 利 用 你 自 已 的eventobject 类 型
让 我 们 看 一 个 创 建eventobject 类 型 的 例 子 。 这 个 例 子 是 在 上 个 月 的 一 个 例 子,barchartbean 的 基 础 上 进 行" 脑 外 科 式"(brain surgery) 的 改 造 而 成 的 。 我 先 在barchartbean 中 增 加 代 码, 以 使 得 在bar 区 域 内, 用 户 每 次 点 击 或 拖 动 鼠 标 时, 都 重 先 设 置percent 属 性 。 这 为 我 们 提 供 了 一 个 通 过 鼠 标 来 改 变percent 属 性 的 方 法 。

barchartbean 通 过 预 先 定 义 的propertychangelistener 接 口( 在java 。beans 包 中 定 义 的, 通 用 的 事 件 监 听 器 接 口), 来 通 知 其 它 对 象 它 的percent 属 性 变 化 情 况 。 现 在, 我 们 通 过 定 义 一 个 新 的 事 件 类 型,percentevent, 为 外 部beans 增 加 另 一 个 方 法, 以 使 这 些beans 能 够 被 通 知 到 每 一 次percent 的 变 化 。

import java.util.*;

//
//该类封装每一次percent属性的变化,并将变化传递给"percentlistener".
//

public class percentevent extends java.util.eventobject
{
protected int iold_, inew_;

public percentevent(object source, int iold, int inew)
{
super(source);
iold_ = iold;
inew_ = inew;
}

public int getoldpercent() { return iold_; }

public int getpercent() { return inew_; }

public int getchangedby() { return inew_ - iold_; }
}

你 是 否 还 记 得, 在 前 面 我 们 曾 提 到 过 在 事 件 中 封 装 类 规 范(class-specific) 数 据? 妤 了, 在 此, 新 的 和 旧 的 百 分 比 值 都 规 范 于percentevent 事 件 类 。

现 在, 让 我 们 为 这 一 新 的 事 件 类 型 定 义 一 个 监 听 器 接 口 。

import java.util.*;

//每一个想监听"percent"变化情况的类都
//应该实现这个接口

public interface percentlistener extends eventlistener
{
public void percentchanged(eventobject e);
}

接 下 来, 我 们 要 把barchartbean 变 成 为 一 个percentevent 的 源 。 为 达 此 目 的, 我 们 将 在barchartbean 中 实 现addpercentlistener() 和removepercentlistener(), 并 且 无 论 何 时, 当percent 属 性 改 变 时, 都 能 够 去 修 改 所 有 的 监 听 器 。( 在 此, 我 们 只 需 看 源 代 码 中 相 关 的 部 分)

//
// barchart bean现在接收输入
//
public class barchartbean extends canvas
implements serializable, propertychangelistener
{
// ...
// list of percent listeners.
private vector percentlisteners_;

// ... a whole lotta methods...

// set/get methods for percent
public void setpercent(int ipercent)
{
// set new percent, and only if necessary repaint()
// this is the only place that ipercent´s range is controlled
if (ipercent <= 100 && ipercent>= 0)
{
// save old value, set new value first
int prevpercent = ipercent_;
ipercent_ = ipercent;

// notify property listeners of change to "percent" property
pcs_.firepropertychange("percent",
new integer(prevpercent),
new integer(ipercent_));

// notify all listeners for "percent" change
notifypercentchanged(prevpercent, ipercent);

// repaint only if necessary.
if (prevpercent != ipercent_)
{
repaint();
}
}
}

// ...

//
// these methods are for handling "percentlisteners"
//

// add a new percent listener
public synchronized void addpercentlistener(percentlistener listener)
{
percentlisteners_.addelement(listener);
}

// remove a percent listener
public synchronized void removepercentlistener(percentlistener listener)
{
percentlisteners_.removeelement(listener);
}

// notify all listeners that "percent" changed
protected void notifypercentchanged(int oldpct, int newpct)
{
vector thislist = new vector();
percentevent thisevent = new percentevent(this, oldpct, newpct);

// make a copy of the list so potential changes to it by
// other threads won´t affect traversal.
synchronized (this)
{
thislist = (vector)percentlisteners_.clone();
}

// send a "percentevent" to every listener.
for (int elem = 0; elem

矢 量percentlisteners_ 是 一 列 当percent 属 性 改 变 时, 需 要 被 通 知 的percentlisteners( 实 现 了percentlistener 接 口 的 对 象) 清 单。 在 源 程 序 的 更 下 方, 以 前 的setpercent() 方 法 调 用firepropertychange(), 而 现 在, 它 还 调 用notifypercentchanged() 以 通 知 在percentlisteners_ 清 单 中 的 所 有 对 象。( 在 此, 实 际 上, 我 们 提 供 了 两 种 通 知percent 变 化 的 方 法:( 以 前 的) 作 为 一 个propertychange, 和 现 在 的 作 为 一 个percentevent。)

addpercentlistener() 和removepercentlistener() 方 法 仅 仅 向 监 听 器 清 单 中 追 加 或 从 清 单 中 删 除 对 象。 追 加 和 删 除 同 步 进 行, 因 为 多 线 索 将 尽 可 能 向 清 单 中 追 加 或 从 清 单 中 删 除 监 听 器。 如 果 在 处 理 这 一 列 清 单 的 过 程 中, 发 生 一 个 上 下 文 转 换(a context switch), 那 么 可 怕 的 事 情 将 会 发 生。( 这 个 清 单 可 能 被 毁 坏。 如 果 你 足 够 幸 运, 它 可 能 会 导 致 错 误 难 以 查 找; 如 果 你 不 幸 运 的 话, 它 将 会 使 应 用 程 序 行 为 不 可 预 测, 更 有 胜 之, 毁 坏 数 据。)

实 质 上 的 工 作 是 在notifypercentchanged() 中 进 行 的。 根 据 输 入 的 数 据, 它 将 创 建 一 个 新 的percentevent 事 件, 接 着percentlisteners_ 清 单 将 被 克 隆, 也 就 是 说, 它 将 被 彻 底 复 制 到 一 个 新 的 矢 量 中。synchronized 关 键 词 暗 示 我 们 为 什 么 这 样 做 的 理 由: 当 我 们 部 分 遍 历 这 一 清 单 时, 另 一 条 线 索 正 要 删 除 某 一 监 听 器, 那 会 出 现 什 么 情 况 呢?( 参 见 前 一 段 中 的" 可 怕 事 件"。)notifypercentchanged() 中 的 循 环 只 简 单 地 根 据 我 们 创 建 的 清 单, 将percentevent 事 件 传 递 给 所 有 的 监 听 器。

当 然, 如 果 没 有 事 件 目 标, 一 个 事 件 源 对 于 我 们 也 没 有 任 何 价 值。 下 面, 我 们 将 创 建 一 个bean, 它 其 实 是 一 条 标 签, 能 够 在 接 收 到 一 个percentevent 事 件 后, 随 之 改 变。

import java.util.*;
import java.io.*;
import java.awt.*;
import percentlistener;
import percentevent;

public class percentlabel
extends label
implements serializable, percentlistener
{
public percentlabel() { }

public void percentchanged(eventobject event)
{
if (event instanceof percentevent)
{
percentevent pe = (percentevent) event;
settext(integer.tostring(pe.getpercent()));
}
}
}

上 面 例 子 非 常 简 单。 现 在,我 们 所 要 做 的 就 是 将 二 者 连 接 起 来:

import java.awt.*;
import java.io.*;
import barchartbean;

public class example
extends panel
implements serializable
{
private percentlabel pl_ = new percentlabel();
private barchartbean bcb_ = new barchartbean();

public example()
{
bcb_.addpercentlistener(pl_);
setlayout(new borderlayout());
add("north", pl_);
add("south", bcb_);
}
}

下 面 就 是 所 得 到 的bean:



percentchange事 件 工 作 正 常

你 可 以 下 载jar 文 件 并 在beanbox 中 自 己 试 着 这 样 做。

现 在 的 问 题 是, 既 然propertychange 接 口 已 经 存 在, 那 么, 为 什 么 每 个 人 都 还 想 去 做 额 外 的 工 作, 来 创 建 他 们 自 已 的 事 件 类 型 呢? 一 个 可 能 的 原 因 是, 同propertychange 所 允 许 传 递 的 信 息 相 比, 在 事 件 中, 你 能 够 传 递 更 多 的 信 息。 你 可 以 在 一 个 事 件 中, 封 装 你 所 想 要 的 任 何 东 西。 实 际 上, 上 一 个 月 我 们 所 见 到 的propertychange 机 制 其 实 是 根 据 我 们 刚 才 所 见 的 事 件 监 听 器 实 现 的。

事 件 也 比propertychange 更 加 通 用。 新 的awt 定 义 了 诸 如 鼠 标 移 动、 敲 击 键 盘、 调 整 组 件 大 小 等 等 的 事 件 类 型。 你 可 能 想 在 你 的 应 用 程 序 中, 为 这 些 新 的 事 件, 分 别 定 义 一 个 新 的 事 件 处 理 类, 并 且 使 得 他 们 不 全 都 去 本 能 地 模 仿propertychange。 例 如, 在 一 个modemcontrol bean 中, 你 可 以 创 建 一 个 新 的modemevent 类, 并 创 建 一 个 适 当 的 监 听 器 接 口, 使 其 它beans 能 够 监 听 到 诸 如modemconnectevent,modemdisconnectevent 等 等 之 类 的 事 件。 这 种 做 法 将 比 有 一 个 被 称 为"modemstate"( 或 其 它 什 么 的) 属 性 的 做 法 更 为 合 理。 后 者 的 做 法 中,"modemstate" 属 性 在 有 些 情 况 下 只 能 读 出(read only), 而 其 他 的 情 况 下 既 可 读 又 可 写, 其 实 并 不 是 真 正 意 义 上 的" 属 性"。

ides 能 够 利 用 新 的java 映 像 机 制, 这 种 机 制 可 使java 程 序 分 析 类 文 件, 以 分 析beans。ides 能 够 寻 找 实 现eventlistener 的 类( 以 找 出 事 件 的 目 标), 并 能 够 寻 找 名 字 象addsomethinglistener() 的 方 法( 以 找 出 事 件 的 源)。( 请 记 住 上 面 关 于 空 的eventlistener 接 口 对ides 有 用 的 评 论- 这 就 是 有 用 的 原 因。) 你 也 可 以 在 你 的beans 中 增 加 方 法 以 明 确 地 告 诉ides( 或 其 它 任 何 提 问 者) 你 的bean 产 生 或 处 理 什 么 事 件。

我 们 刚 刚 手 工 编 写 了 一 个 名 为example 的 类, 它 能 够 利 用 某 个 监 听 器 接 口 使 一 个bean 和 另 一 个bean" 接 通"。 在 此, 我 们 将 把 它 做 得 更 好, 利 用 可 视 化 编 程 环 境 实 现 同 样 的 功 能。 下 面 的 几 步 将 在beanbox 上 实 现。

在 你 的jars 目 录 中, 打 开 带 有colorbar。jar 的beanbox, 以 使 得example bean 能 被 装 载。

向beanbox 中 增 加 一 个barchartbean。

往beanbox 中 加 入 一 个percentlabel( 最 好 将 其 变 为 白 色, 以 便 容 易 看 到)。

选 择 在beanbox 中 的barchartbean。

选 择 菜 单 项edit->events->percent->percentchanged。 现 在 你 能 够 看 到:beanbox 自 动 地 识 别 新 的 事 件 类 型 并 将 其 加 入 到 事 件 列 表 清 单 中, 这 一 清 单 你 可 从barchartbean 中 得 到。 真cool!

你 需 要 一 条 红 色 的 橡 皮 带 式 生 成 线。 移 动 鼠 标 到percentlabel 上, 并 点 击 它。

一 个 对 话 框 将 出 现, 问 你 当 一 个percentchanged 事 件 到 达percentlabel 时, 你 希 望 选 择 调 用 哪 一 个 方 法。 你 选 择percentchanged。
beanbox 创 建 一 个"adaptor" 类, 它 即 是 一 个percentlistener。

接 下 来,beanbox 编 译 它 所 写 的adaptor 类, 创 建 一 个 实 例, 并 且 利 用barchartbean。addpercentlistener() 调 用 它。 一 旦barchartbean 产 生 了percent 事 件, 它 将 这 些 事 件 传 递 给adaptor( 因 为adaptor 是 一 直 在" 监 听"),adaptor 接 着 将 事 件 传 递 给percentlistener。percentchanged()。

实 际 上, 下 面 是beanbox 产 生 的"adaptor" 类 的 代 码:

// 自 动 生 成 的 事 件 连 接 文 件.

package tmp.sun.beanbox;
import percentlabel;
import percentlistener;

public class ___hookup_1452f9e502 implements percentlistener, java.io.serializable
{

public void settarget(percentlabel t)
{
target = t;
}

public void percentchanged(java.util.eventobject arg0)
{
target.percentchanged(arg0);
}

private percentlabel target;
}

现 在, 只 须 象 以 前 一 样 应 用barchartbean,percentlistener 就 会 自 动 地 跟 踪percent 事 件。 这 就 是 可 视 化 的 应 用 程 序 开 发。
如 果 你 的 浏 览 器 支 持 动 态gif 文 件, 请 访 问 该 地 址(http://www。javaworld。com/javaworld/jw-10-1997/images/percentdemo.gif) 以 看 到 这 一 过 程 的 动 态 演 示。

bean-a-palooza: 为 同 一 类 型 的 事 件 分 组
在 你 写 监 听 器 接 口 的 时 候, 应 当 注 意 到, 通 常 情 况 下, 仅 创 建 一 个 监 听 器 接 口, 使 其 包 括 一 个 若 干 相 关 事 件 共 用 的eventtypeperformed() 方 法, 比 为 每 一 个 事 件 都 创 建 一 个 监 听 器 接 口 的 做 法 更 加 省 事 而 且 简 便。

关 于 这 种 思 想 的 一 个 好 例 子 是jkd1。1 awt 中 鼠 标 事 件 的 处 理 方 式。( 实 际 上, 其 中 有 两 种 这 样 的 接 口, 根 据 处 理 效 率 的 不 同 要 求, 将 鼠 标 事 件 进 行 分 组)。

为 了 捕 捉 新 的awt 中 的 鼠 标 事 件, 一 个 类 必 须 实 现 的 下 面 两 个 接 口 中 的 一 个 或 者 全 部:java。awt。event。mouselistener 或java.awt.event.mousemotionlistener. 这 两 个 接 口 分 别 包 括 以 下 方 法:

public interface mouselistener extends eventlistener
{
public void mouseclicked(mouseevent e);
public void mouseentered(mouseevent e);
public void mouseexited(mouseevent e);
public void mousepressed(mouseevent e);
public void mousereleased(mouseevent e);
};

public interface mousemotionlistener extends eventlistener
{
public void mousedragged(mouseevent e);
public void mousemoved(mouseevent e);
}

就 目 前 而 言,awt 的 设 计 者 原 本 能 够 非 常 简 便 地 定 义 大 量 的 接 口 和 相 关 的 事 件 类 型:

public interface mouseclicklistener extends eventlistener
{
public void mouseclicked(mouseclickevent e);
}

public interface mouseenterlistener extends eventlistener
{
public void mouseentered(mouseenterevent e);
}

// 等 等

但 是,awt 的 设 计 者 其 实 是 将 多 个 方 法 进 行 分 组, 分 别 归 类 到 上 面 所 说 的 两 个 接 口 中。 一 个 需 要 接 收 鼠 标 事 件 的 类 只 须 声 明 它 实 现mouselistener, 并 接 着 实 现 所 有 的 诸 如void mouseclicked(mouseevent e), void mouseentered(mouseevent e) 等 等 之 类 的 方 法, 即 可 当 事 件 发 生 时, 能 够 去 做 任 何 需 要 做 的 事。 如 果 你 对mouseexits 事 件 不 感 兴 趣, 你 所 要 做 的 仅 仅 就 是 使 这 一 方 法 不 做 任 何 事 情。( 实 现 一 个 接 口 时,java 需 要 其 中 所 有 的 方 法 都 被 定 义。 如 果 接 口 中 的 所 有 方 法 没 有 被 完 全 被 定 义, 那 么 你 的 类 将 不 能 通 过 编 译。 当 然 也 有 办 法 绕 过 这 一 情 况-- 可 参 见 下 面 的"do nothing 类"。)

为 什 么java 设 计 者 不 将 所 有 的 鼠 标 事 件 处 理 方 法 都 归 入 到 同 一 个 接 口 中, 而 是 将 这 些 方 法 分 成 两 类 分 别 归 到mouselistener 和mousemotionlistener 两 个 接 口 中 呢? 这 涉 及 到 一 个 性 能 问 题: 鼠 标 移 动 事 件 出 现 频 率 高 而 且 速 度 快, 远 远 快 于 点 击 鼠 标 按 钮 的 速 度。 如 果 实 际 运 行 中, 没 有 一 个 类 来 监 听 鼠 标 的 移 动, 那 么,awt( 内 部 地) 就 会 丢 弃 它 所 接 收 到 的 任 何 此 类 事 件, 以 节 省 时 间, 而 不 将 时 间 浪 费 在 调 用 一 个 其 实 并 不 做 任 何 事 情 的 方 法 之 上。

在 前 面, 我 已 提 到 了 将 要 进 一 步 讨 论 的 一 个 办 法, 它 希 望 绕 过java 恼 人 的 而 且 顽 固 坚 持 的 行 径: 一 个 接 口 中 的 所 有 方 法 都 必 须 被 定 义, 即 使 这 些 方 法 不 做 任 何 事 情。 下 面 我 们 将 写 一 个 类, 它 将 跟 踪 并 保 存 下 鼠 标 被 点 击 的 次 数。 这 个 类 的 相 关 部 分 大 致 如 下:

// count right mouse clicks
public class clickcounter extends panel implements mouselistener
{
private int iclicks_ = 0;

// listen for events on self
clickcounter() { addmouselistener(this); }

public void mouseclicked(mouseevent e) { iclicks_++; repaint();}
public void mouseentered(mouseevent e) { }
public void mouseexited(mouseevent e) { }
public void mousepressed(mouseevent e) { }
public void mousereleased(mouseevent e) { }
public void paint() { // paint the # of clicks on the panel }
}

从 上 可 以 注 意 到, 必 须 定 义 许 多 无 用 的 空 函 数 的 确 是 件 恼 人 的 事。 所 幸 的 是,awt 的 设 计 者 为 你 解 决 了 这 一 难 题: 他 们 创 造 了 不 做 任 何 事 情 的 类。

不 做 任 何 事 情 的 类(do-nothing classes)
java。awt。event。mouseadapter 类 所 要 做 的 事 就 是 不 做 任 何 事 情。 它 实 现mouselistener 类, 并 且 它 的 方 法 丢 弃 所 接 收 到 事 件。 其 方 法 不 做 任 何 事 件 的 类 能 够 有 什 么 用 途 呢? 对 于 类 自 身 而 言, 几 乎 一 无 所 用 ? ? 然 而, 你 可 以 创 建 一 个mouseadapter 的 子 类, 并 在 子 类 中 仅 仅 实 现 那 些 你 感 兴 趣 的 方 法。 上 面 所 说 的clickcounter 例 子 现 在 可 以 这 样 实 现:

public class clickcounter extends mouseadapter
{
private int iclicks_ = 0;

// listen for events on self
clickcounter() { addmouselistener(this); }

public void mouseclicked(mouseevent e) { iclicks_++; repaint();}
public void paint() { // paint the # of clicks on the panel }
}

与 前 面 的 将 类 定 义 为 实 现mouselistener 的 做 法 不 同, 在 这 里, 类 的 定 义 通 过 扩 展mouseadapter 完 成, 并 且 将mouseadapter 类 中 不 做 任 何 事 的 函 数 斩 草 除 根( 因 此 你 就 不 必 写 出 那 些 不 做 任 何 事 的 方 法)。 你 要 写 的 所 有 的 函 数 就 是mouseclicked(), 它 也 就 是 你 所 感 兴 趣 的 所 有 事 情。 这 难 道 不 够 方 便 吗?

你 将 会 发 现, 在awt 中 的 绝 大 多 数 的 事 件 监 听 器 接 口 群 组 都 包 括 三 个 相 关 的 定 义:

eventtypeevent: 所 发 生 的 事 件

eventtypelistener: 事 件 监 听 接 口

eventtypeadapter: 不 做 任 何 事 件 的adaptor 类, 你 可 因 此 而 不 必。。。
所 有 这 些 对 于beans 的 重 要 意 义 是:

当 为 你beans创 建 事 件 监 听 接 口 时:

在 事 件 监 听 器 接 口 中, 为 相 关 的 事 件 类 型 分 组

如 果 在 接 口 中 有 多 个 方 法, 提 供 一 个adapter 类 以 使 你 的 接 口 更 容 易 应 用。
内 嵌 类
现 在, 想 象 你 有20 个 用 户 接 口widget 类 型, 并 且 当 某 一mouseevent 事 件 发 生 时, 这 些 接 口 类 型 各 自 做 不 同 的 事 情。 你 的 名 字 空 间 将 会 被 诸 如:drawpanemouseevent,mousepositionmouseevent 等 等 的 各 种 事 件 处 理 类 弄 得 混 杂 不 堪。 而 且 这 些 类 都 仅 仅 能 够 被 用 于 那 些" 拥 有" 它 们 的 类。java 1。1 中, 有 一 种 名 为 内 嵌 类 的 新 机 制 允 许 你 来 控 制 类 的 定 义 范 围。

在java 中, 内 嵌 类 是 在 另 一 个 类 中 定 义 的 类。 它 的" 活 动 范 围"( 或" 可 见 范 围") 仅 仅 限 于 类 被 定 义 时 所 在 的 块。

内 嵌 类 是java1。1 的 新 特 性, 它 对 于 定 义 某 些adaptor 类 是 十 分 有 用 的, 这 些 类" 通 晓" 它 们 所 操 纵 的 对 象 的 实 现 详 情。clickcounter 提 供 了 这 样 的 一 个( 非 常 简 单 的) 例 子:

public class clickcounter extends panel
{
private int iclicks_ = 0;

class mousehandler extends mouseadapter
{
public void mouseclicked(mouseevent e)
{ iclicks_++; repaint();}
}

// listen for events on self
clickcounter() { addmouselistener(new mousehandler()); }

public void paint() { // paint the # of clicks on the panel }
};
// 下 面 的 语 句 不 合 法, 将 不 会 通 过 编 译!
mousehandler m = new mousehandler();

上 面 的 程 序 对 被 称 为mousehandler 的 内 嵌 类 的 点 击 鼠 标 事 件 进 行 推 迟 处 理。 这 个 类" 知 道" 包 括 它 的 类 所 拥 有 的 变 量"iclicks"。 如 果 你 企 图 在 一 个" 顶 层" 类( 也 就 是 说, 任 何 不 是 内 嵌 类 的 类) 中 这 样 做, 那 么, 你 就 不 可 能 得 到clickcounter 中(iclicks 的) 具 体 的 实 现 情 况。 你 将 不 得 不 增 加 一 些 方 法 来 控 制 点 击 的 计 数, 这 样 一 来, 你 也 破 坏 了 封 装 机 制。( 词 语" 顶 层 类"(top-level class) 是 一 个retronym, 就 是 说, 它 是 对 旧 事 物 的 一 个 新 名 字。)

在 此 例 中, 我 故 意 包 括 了 一 个 错 误: 在clickcounter 类 的 范 围 之 外, 定 义 了 一 个mousehandler 对 象。 程 序 在 编 译 时 将 会 出 错, 因 为mousehandler 并 不 是 在clickcounter 类 之 外 定 义 的。 如 果 某 一 顶 层 类 碰 巧 被 命 名 为mousehandler, 那 么 代 码 将 会 正 常 被 编 译, 但mousehandler m 将 不 会 与clickcounter 的 内 嵌 类 同 型。 应 该 看 到: 用 这 种 办 法 分 离 名 字 空 间 是 内 嵌 类 的 一 个 目 的。

内 嵌 类 有 一 个 值 得 引 起 注 意 的 地 方 是: 虽 然 它 们 的 范 围 不 同 于 顶 层 类 的 范 围, 但 每 一 个 你 定 义 的 内 嵌 类 都 被 编 译 到 它 自 己 的 类 文 件 中。 在win32 系 统 中, clickcounter 的 内 嵌 类 文 件 名 将 会 是clickcounter$mousehandler。class。 ( 核 查 你 的 文 件 或 做 一 点 小 试 验, 来 看 一 看 在 你 的 系 统 上 它 是 怎 么 工 作 的。) 这 里 值 得 注 意 的 是, 即 使 这 些 内 嵌 类 不 是beans, 你 的beans 所 定 义 的 每 一 个 内 嵌 类 将 会 用 到 它 们 的( 内 嵌) 类 文 件, 否 则,beans 将 不 会 转 动。 所 以, 一 定 要 在 你 的jar 文 件 中 包 括 你 所 定 义 的 内 嵌 类 所 用 到 的 类 文 件。

如 果 你 还 想 参 看 另 一 个 利 用 内 嵌 类 事 件adaptor 处 理 鼠 标 事 件 的 例 子, 你 可 以 查 阅barchartbean 的 源 码。 参 见 下 面 的resources, 你 可 以 获 得 此 源 码 及 更 多 的 有 关 内 嵌 类 的 信 息( 其 中 有 些 东 西 的 确 不 可 思 意)。

张 智 雄 编 译 自:http://www.javaworld.com/javaworld/jw-05-1997/jw-05-step.html
 
 
上一篇: 事件处理中ui的刷新问题(笔记体小品文)    下一篇: 鼠标事件和键盘事件
  相关文档
浅析j2ee、j2se和j2me 11-16
我学习使用java的一点体会 11-17
4类java技术平行发展sun公司计划谋求“统一” 11-17
java 理论与实践: 用jmx检测应用程序 11-17
mini java编译器(三)——属性翻译文法 11-17
安全的基础--学习java安全之前的准备 11-17
使tostring()的创建自动化 11-17
技巧实例:如何在.net中访问mysql数据库 (1) 09-25
j2se综合--java能替代c语言的可能性 12-27
对比两个不同版本的assertequals() 11-17
对java同步一些理解 11-17
java高级日期概念二 11-17
java程序,向网站发送垃圾留言 11-17
轻量组件与重量组件的比较 11-17
用java实现利用搜索引擎收集网址的程序 11-16
在spring mvc框架中显示xml视图 11-17
给javabeans增加xpath功能 11-17
不使用function计算给定两个日期之间的工作日个数 11-17
java基础:泛型类型的子类及通配符的使用 11-29
如何使用eclipseme开发j2me程序 11-17
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
技术电话:13616026886
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息