About The Site

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Phasellus a erat. Nulla quis felis quis libero ultricies vestibulum. Etiam eros elit, porttitor vel, imperdiet venenatis, tristique vel, lacus. Nunc eros lacus, condimentum ut, suscipit id, elementum ut, eros. Sed lorem. Proin aliquet suscipit sapien. Cras sit amet nulla. Aenean vitae metus. Suspendisse elementum varius mi. Duis malesuada, turpis ut luctus faucibus, justo leo tristique.

DELPHI中的消息处理机制

DELPHI中的消息处理机制

发信人: strayli (stray), 信区: Delphi
标 题: DELPHI 中 的 消 息 处 理 机 制 (转)
发信站: BBS 水木清华站 (Sun Oct 4 18:29:01 1998)


DELPHI 中 的 消 息 处 理 机 制


( 南 京 理 工 大 学 自 控 系 研96 马 勇
邮 编:210094 电 话:025-4315309 )


Delphi 是Borland 公 司 提 供 的 一 种 全 新 的WINDOWS 编 程 开 发 工 具. 由 于 它 采 用 了 具 有 弹 性 的 和 可 重 用 的 面 向 对 象Pascal(object-oriented pascal) 语 言, 并 有 强 大 的 数 据 库 引 擎(BDE), 快 速 的 代 码 编 译 器, 同 时 又 提 供

众 多 出 色 的 构 件. 受 到 广 大 编 程 人 员 的 青 睐. 在 众 多 的 编 程 语 言( 如VB,PowerBuilder,Powerpoint 等) 中 脱 颖 而 出.

其 中 一 个DELPHI 强 于 其 他 编 程 语 言( 如VB4.0) 的 地 方 就 是 在DELPHI 中 可 自 定 义 消 息, 并 可 直 接 处 理 消 息. 这 对 于 那 些 希 望 编 写 自 己 的 构 件(Component), 或 者 希 望 截 获. 过 滤 消 息 的 用 户 来 说 是 必 不 可 少 的. 因 为
编 写 构 件 一 般 要 对 相 应 的 消 息 进 行 处 理. 下 面 就 对Delphi 中 消 息 处 理 机 制 进 行 一 下 介 绍。

一.DELPHI VCL 中 消 息 的 传 递

Delphi 中 每 一 个VCL(Visual Component Library) 构 件( 如Tbutton,Tedit 等) 都 有 一 内 在 的 消 息 处 理 机 制, 其 基 本 点 就 是 构 件 类 接 收 到 某 些 消 息 并 把 它 们 发 送 给 适 当 的 处 理 方 法, 如 果 没 有 特 定 的 处 理 方 法, 则 调 用
缺 省 的 消 息 处 理 句 柄。

其 中mainwndproc 是 定 义 在Twincontrol 类 中 的 一 个 静 态 方 法, 不 能 被 重 载(Override)。 它 不 直 接 处 理 消 息, 而 是 交 由wndproc 方 法 处 理, 并 为wndproc 方 法 提 供 一 个 异 常 处 理 模 块。Mainwndproc 方 法 声 明 如 下:

procedure MainWndProc(var Message: TMessage);

Wndproc 是 在Tcontrol 类 中 定 义 的 一 个 虚 拟 方 法, 由 它 调 用dispatch 方 法 来 进 行 消 息 的 分 配, wndproc 方 法 声 明 如 下:

procedure WndProc(var Message: TMessage); virtual;

dispatch 方 法 是 在Tobject 根 类 中 定 义 的, 其 声 明 如 下:

procedure Tobject.dispatch(var Message); 传 递 给dispatch 的 消 息 参 数 必 须 是 一 个 记 录 类 型, 且 这 个 记 录 中 第 一 个 入 点 必 须 是 一 个cardinal 类 型 的 域(field), 它 包 含 了 要 分 配 的 消 息 的 消 息 号 码. 例 如:

type

Tmessage=record

Msg:cardinal;

wparam:word;

lparam:longint; .

result:longint;

end;


而Dispatch 方 法 会 根 据 消 息 号 码 调 用 构 件 的 最 后 代 类 中 处 理 此 消 息 的 句 柄 方 法. 如 果 此 构 件 和 它 的 祖 先 类 中 都 没 有 对 应 此 消 息 的 处 理 句 柄,Dispatch 方 法 便 会 调 用Defaulthandler 方 法.Defaulthandler 方 法 是 定
义 于Tobject 中 的 虚 拟 方 法, 其 声 明 如 下:

procedure Defaulthandler(var Message);virtual;

Tobject 类 中 的Defaulthandler 方 法 只 是 实 现 简 单 的 返 回 而 不 对 消 息 进 行 任 何 的 处 理. 我 们 可 以 通 过 对 此 虚 拟 方 法 的 重 载, 在 子 类 中 实 现 对 消 息 的 缺 省 处 理. 对 于VCL 中 的 构 件 而 言, 其Defaulthandler 方 法 会 启
动 windows API 函 数Defwindowproc 对 消 息 进 行 处 理.

二.DELPHI 中 的 消 息 处 理 句 柄

在DELPHI 中 用 户 可 以 自 定 义 消 息 及 消 息 处 理 句 柄. 消 息 处 理 句 柄 的 定 义 有 如 下 几 个 原 则:

1.消 息 处 理 句 柄 方 法 必 须 是 一 个 过 程, 且 只 能 传 递 一 个Tmessage 型 变 量 参 数. 2.方 法 声 明 后 要 有 一 个message 命 令, 后 接 一 个 在0 到32767 之 间 的 消 息 标 号( 整 型 常 数). 3.消 息 处 理 句 柄 方 法 不 需 要 用override 命 令 来
显 式 指 明 重 载 祖 先 的 一 个 消 息 处 理 句 柄, 另 外 它 一 般 声 明 在 构 件 的protected 或private 区. 4.在 消 息 处 理 句 柄 中 一 般 先 是 用 户 自 己 对 消 息 的 处 理, 最 后 用inherited 命 令 调 用 祖 先 类 中 对 应 此 消 息 的 处 理 句 柄(
有 些 情 况 下 可 能 正 相 反). 由 于 可 能 对 祖 先 类 中 对 此 消 息 的 处 理 句 柄 的 名 字 和 参 数 类 型 不 清 楚, 而 调 用 命 令inherited 可 以 避 免 此 麻 烦, 同 样 如 果 祖 先 类 中 没 有 对 应 此 消 息 的 处 理 句 柄,inherited 就 会 自 动 调
用Defaulthandler 方 法.( 当 然 如 果 要 屏 蔽 掉 此 消 息, 就 不 用inherited 命 令 了)。

消 息 处 理 句 柄 方 法 声 明 为:
procedure Mymsgmethod(var message:Tmessage); message Msgtype;

同 样 用 户 也 可 以 定 义 自 己 的 消 息, 用 户 自 定 义 消 息 应 从WM_USER 开 始.

自 定 义 消 息 及 消 息 处 理 句 柄 举 例 如 下:

const my_paint=Wm_user+1;

type

Tmypaint=record

msgid:cardinal;

msize:word;

mcolor:longint;

msgresult:longint;

end;

type

Tmycontrol=class(TCustomControl)

protected

procedure change(var message:Tmypaint); message my_paint;

.....

end;

......

procedure Tmycontrol.change(var message:Tmypaint);

begin

size:=message.msize; { 设 置Tmybutton 尺 寸 属 性}

color:=message.mcolor; { 设 置Tmybutton 颜 色 属 性}

{do something else}

inherited; { 交 由Tcustomcontrol 处 理}

end;




三. 过 滤 消 息

过 滤 消 息 又 称 消 息 陷 阱。 在 一 定 情 况 下, 用 户 可 能 需 要 屏 蔽 某 些 消 息. 或 者 截 获 某 些 消 息 进 行 处 理。 由 以 上 介 绍 可 以 看 出 过 滤 消 息 一 般 有 三 种 途 径:(1). 重 载 构 件 继 承 的 虚 拟 方 法wndproc. (2). 针 对 某
消 息 编 写 消 息 处 理 句 柄. (3). 重 载 构 件 继 承 的 虚 拟 方 法Defhandler, 在 其 中 对 消 息 进 行 处 理。 其 中 常 用 的 方 法 是 方 法(2), 在 上 节 中 已 介 绍 过 了, 方 法(1) 与 方 法(3) 相 似, 这 里 只 简 单 介 绍 一 下 方 法(1)。

重 载 虚 拟 方 法wndproc 的 一 般 过 程 如 下:

procedure Tmyobject.wndproc(var message:Tmessage);

begin

{... 判 断 此 消 息 是 否 该 处 理..}

inherited wndproc(message);

{ 未 处 理 的 消 息 交 由 父 辈wndproc 方 法 处 理}

end;


由 此 可 以 看 出 在wndproc 方 法 中 处 理 消 息 的 优 势 是 可 以 过 滤 整 个 范 围 内 的 消 息, 而 不 必 为 每 个 消 息 指 定 一 个 处 理 句 柄, 事 实 上Tcontrol 构 件 中 就 是 利 用 它 来 过 滤 并 处 理 所 有 的 鼠 标 消 息 的(
从WM_mousefirst 到WM_mouselast, 如 下 代 码 示). 同 样 利 用 它 也 可 以 阻 止 某 些 消 息 被 发 送 给 处 理 句 柄。

procedure TControl.WndProc(var Message: TMessage);

begin

if (Message.Msg>=WM_MOUSEFIRST) and

(Message.Msg <= WM_MOUSELAST)

then

if Dragging then { 处 理 拖 曳 事 件}

DragMouseMsg(TWMMouse(Message))

else

... { 处 理 其 他 鼠 标 消 息}

end;

Dispatch(Message);

{ 否 则 正 常 发 送 消 息}

end;


下 例 为 一 简 单 的 自 定 义 构 件 例 子 :

Tmyedit 类 是 从Tedit 类 派 生 出 的 一 个 新 类, 它 的 特 点 是 在 运 行 中 不 能 获 得 焦 点, 不 能 由 键 盘 输 入( 有 点 类 似Tlabel 构 件). 我 们 可 在 其wndproc 方 法 中 过 滤 出WM_setfocus,WM_mousemove 消 息 并 进 行 处 理 来 达 到 上 述
要 求, 源 程 序 如 下:

unit myedit;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs,

StdCtrls;

type

Tmyedit = class(TEdit)

private

{ Private declarations }

protected

{ Protected declarations }

{ other fields and methods}

procedure wndproc(var message:Tmessage);override;

public

{ Public declarations }

published

{ Published declarations }

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('Samples', [Tmyedit]);

end;

procedure Tmyedit.wndproc(var message:tmessage);

begin

if message.msg=wm_mousemove then

begin

cursor:=crarrow;

{ 设 置 光 标 为crarrow, 而 不 是 缺 省 的crBeam 光 标}

exit;

end;

if message.msg=wm_SetFocus then exit;

{屏蔽掉WM_setfocus消息,不让Tmyedit控件获得输入焦点}

inherited wndproc(message);

{其他消息交父辈wndproc处理}

end;

end.


您 可 以 将Tmyedit 加 到Component Palette 中 检 验 其 性 能。

由 以 上 介 绍 可 以 看 出, 只 有 清 楚 了Delphi VCL 中 的 消 息 处 理 机
制, 掌 握 好 处 理 各 种 消 息 的 方 法 和 时 机( 必 要 时 要 借 助 各 种 工
具, 如winsight32,spy 等), 并 结 合OOP 语 言 的 特 点, 我 们 才 可 能 编
出 高 质 量 的 构 件。 这 当 然 要 靠 读 者 在 实 践 中 不 断 摸 索, 积 累 经
验。