国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

事件監聽器?將JavaBeans接通起來的方法

2019-11-18 15:15:32
字體:
來源:轉載
供稿:網友

  摘 要 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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 邮箱| 特克斯县| 德江县| 罗江县| 阳高县| 布尔津县| 湘潭市| 遵义市| 侯马市| 偃师市| 阳曲县| 永胜县| 安远县| 托里县| 泰安市| 海安县| 建瓯市| 阳山县| 原阳县| 启东市| 湖北省| 泗水县| 丽江市| 鹤岗市| 商水县| 察哈| 浦江县| 公主岭市| 内黄县| 湛江市| 麻栗坡县| 深泽县| 察隅县| 晋宁县| 白玉县| 平远县| 高雄县| 沙田区| 普兰店市| 玉屏| 湟中县|