M
mzr
Unregistered / Unconfirmed
GUEST, unregistred user!
最近由于工作需要,接触autocad二次开发,但在delphi下进行cad的二次开发的资料在网上几乎很少,大部分是VBA(与delphi类似),而在大富翁论坛上也是几乎很少提起。似乎这是delphi的一个边缘学科,其实autocad在各个行业应用很广泛,特别是工程和机械行业。
希望有用delphi进行cad二次开发的富翁们做一点贡献,在CAD领域发挥光大delphi!
现我将在网上找到的资料整理出来:
1、Delphi 在AutoCAD 二 次 开 发 中 的 应 用
一、 引 言
---- AutoCAD 是 世 界 上 使 用 范 围 最 广 的CAD 系 统, 基 于 其 之 上 的 二 次 开 发 一 直 有 很 大 的 市 场 需 求。 最 初, 这 些 二 次 开 发 只 能 使 用AutoLISP 进 行, 这 是 一 种 解 释 型 的 编 程 语 言, 执 行 效 率 较 低, 而 且 稳 定 性 较 差。 从R11.0 版 以 后,AutoCAD 推 出 了ADS 接 口, 支 持 用C 语 言 进 行 开 发。 到R13 版 后, 又 推 出 了ARX 接 口, 支 持C++ 语 言。 但 这 两 种 接 口 的 程 序 设 计 都 较 为 繁 琐, 不 利 于 推 广。 从R14 版 开 始,AutoCAD 开 始 支 持ActiveX Automation 技 术, 这 一 方 面 提 供 了 一 种 安 全 而 稳 定 的 二 次 开 发 接 口, 另 一 方 面 又 大 大 简 化 了 程 序 设 计 的 工 作, 使 基 于AutoCAD 的 二 次 开 发 进 入 了 一 个 新 的 阶 段。
---- ActiveX Automation 是 一 种 专 用 于 使Windows 下 应 用 程 序 相 互 联 系 的 技 术, 其 前 身 是OLE Automation 技 术。ActiveX Automation 分 为 两 层:Automation Server 和Automation Controller。
---- Automation Server 是 一 种 应 用 程 序, 它 把 自 身 或 自 身 的 一 部 分 进 行 打 包 后, 作 为 一 个 完 整 的 对 象 输 出。 当 它 第 一 次 运 行 时, 它 会 在 系 统 的 注 册 表 中 写 入 注 册 信 息, 包 括 对 象 的 注 册 名、 注 册 号 和 完 整 的 执 行 路 径。 有 了 这 些 注 册 信 息 后,Automation Controller 应 用 程 序 就 可 以 按 照 对 象 的 注 册 名 向 系 统 申 请。 如 果 申 请 得 到 认 可, 系 统 就 会 生 成 一 个 该 对 象 的 实 例, 并 把 该 实 例 的 句 柄 传 给Automation Controller 应 用 程 序。 通 过 这 个 句 柄,Automation Controller 应 用 程 序 就 可 以 使 用 该 对 象 实 例 提 供 的 全 部 功 能 了。ActiveX Automation 是 完 全 独 立 于 语 言 的 技 术, 也 就 是 说, 可 以 用 任 何 一 种 程 序 设 计 语 言 来 开 发Automation Server 和Automation Controller 应 用 程 序。
---- AutoCAD 从R14 版 开 始 引 入 了Automation 技 术, 它 把 全 部 的 系 统 功 能 和 函 数 打 包 成 为 一 个 名 为AutoCAD.Application.14 的Automation Server 对 象。 通 过 这 个 对 象, 应 用 程 序 可 以 访 问AutoCAD 的 全 部 功 能。
二、 AutoCAD ActiveX Automation 对 象 体 系 结 构
---- AutoCAD ActiveX Automation 对 象 体 系 结 构 如 下 页 图 所 示。 在 对 象 模 型 中, 处 于 最 高 层 的 对 象 是AutoCAD.Application, 称 为 应 用 对 象, 它 包 含 了AutoCAD ActiveX Automation 对 象 所 提 供 的 全 部 功 能。
---- 在AutoCAD.Application 层 之 下 是Preferences 和Document 子 对 象。Preferences 子 对 象 等 价 于AutoCAD 的Preferences 对 话 框, 它 包 含 了AutoCAD 的 当 前 的 系 统 参 数 设 置。Document 子 对 象 代 表AutoCAD 系 统 中 当 前 活 动 的 图 纸 文 件, 通 过Document 子 对 象 可 以 对 系 统 中 当 前 活 动 的 图 纸 文 件 进 行 所 有 的 处 理。
---- Document 子 对 象 包 含 了 所 有 的 图 纸 信 息 子 层, 有: 模 型 空 间 子 集(ModelSpaceEntities Collection)、 纸 空 间 子 集(PaperSpaceEntities Collection) 和 块 子 集(Blocks Collection) 包 含 所 有 的 三 维 图 形 绘 制 对 象, 用 来 进 行 图 形 文 件 的 绘 制; 字 典 子 集(Dictionaries Collection) 负 责 自 动 拼 写 检 查; 标 注 子 集(DimStyles Collection) 负 责 图 纸 标 注; 组 子 集(Groups Collection) 负 责 当 前 活 动 的 图 纸 文 件 中 所 有 的 组 的 管 理; 层 子 集(Layers Collection) 负 责 当 前 活 动 的 图 纸 文 件 中 层 的 设 置; 线 型 子 集(Linetypes Collection) 管 理 线 型; 已 注 册 应 用 程 序 子 集(RegisteredApp Collection) 管 理 系 统 中 的 外 加 应 用 程 序; 选 择 组 子 集(SellectionSets Collection) 管 理 用 户 在 图 纸 中 所 选 择 的 内 容; 文 本 风 格 子 集(TextStyles Collection) 负 责 文 本 字 符 风 格; 用 户 坐 标 系 子 集(UCSs Collection) 负 责 管 理 用 户 坐 标 系; 视 图 子 集(Views Collection) 负 责 管 理 用 户 视 图; 视 角 子 集(Viewports Collection) 负 责 视 角 转 换 控 制; 打 印 输 出 子 集(Plot) 负 责 控 制 图 形 文 件 的 最 终 输 出 及 打 印 设 置; 应 用 子 集(Utility) 包 含 了 大 量 的 辅 助 函 数, 用 来 进 行 辅 助 计 算。
三、 用Delphi 3 进 行AutoCAD 二 次 开 发
---- 在AutoCAD R14 版 的 在 线 帮 助 中, 对 于AutoCAD ActiveX Automation 的 使 用 有 完 整 的 说 明, 并 有 不 少 例 子, 但 都 是 通 过Visual Basic 来 实 现 的。 考 虑 到ActiveX Automation 的 语 言 独 立 性, 完 全 可 以 用Delphi 来 很 好 的 实 现 它。 下 面 我 就 在 实 现 过 程 中 的 一 些 问 题 谈 谈 个 人 的 体 会。
---- 1、 获 取AutoCAD 的Application 和Document 对 象 的 实 例。
---- 获 取AutoCAD 的Application 和Document 对 象 的 实 例 是 对AutoCAD 进 行Automation 开 发 的 基 础。 在VB 中, 可 以 通 过CreateObject 和GetObject 两 个 函 数 来 取 得 实 例 句 柄, 而 在Delphi 中, 相 应 的 函 数 就 变 为CreateOleObject 和GetActiveOleObject。 请 看 下 面 的 程 序:
procedure TForm1.FormCreate(Sender: TObject);
var
obj_Acad ,obj_Doc: OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application.14');
except
obj_Acad:=CreateOleObject('AutoCAD.Application.14');
end;
obj_Acad.Visible:=True;
obj_Doc:=obj_Acad.ActiveDocument;
end;
---- 在 上 面 的 程 序 段 中, 在 第 三 行 定 义 了 两 个 变 量, 分 别 为obj_Doc 和obj_Acad, 变 量 类 型 为OleVariant。OleVariant 是Delphi 为 提 供 完 全OLE 支 持 而 提 供 的 一 种 特 殊 的 数 据 类 型, 可 以 用 它 来 存 储 任 何 类 型 的 数 据。 但 大 量 的 使 用OleVariant 会 大 大 影 响 程 序 的 运 行 速 度, 故 此 只 有 在 必 要 时 才 使 用 它。
---- 从 第 五 行 开 始 连 接AutoCAD.Application。 首 先, 用 函 数GetActiveOleObject 来 读 取 一 个AutoCAD.Application 的 实 例。 当AutoCAD 有 实 例 处 于 运 行 状 态 时, 这 个 函 数 会 取 到 当 前 运 行 的AutoCAD 的 实 例 句 柄, 并 把 它 赋 值 给obj_Acad; 而 当AutoCAD 没 有 实 例 处 于 运 行 状 态 时, 这 个 函 数 会 抛 出 一 个 异 常。 此 时, 程 序 自 动 进 入except 开 头 的 异 常 处 理 模 块。
---- 在 异 常 模 块 里, 程 序 用 函 数CreateOleObject 生 成 一 个AutoCAD.Application 的 实 例, 并 把 它 的 实 例 句 柄 赋 值 给obj_Acad, 从 而 完 成 与AutoCAD.Application 连 接 的 过 程。
---- 接 下 来, 利 用AutoCAD.Application 的Visible 属 性 把AutoCAD 的 窗 口 显 示 出 来。 然 后, 把 活 动 文 档 的 对 象 句 柄 赋 值 给 变 量obj_Doc。 这 样, 就 完 成 了Application 和Document 对 象 实 例 的 获 取。
---- 另 外, 为 了 支 持OleVariant 数 据 类 型, 必 须 在Delphi 的 单 元 中(Unit) 引 入comObj 单 元 和ActiveX 单 元。
---- 2、 用Delphi 在AutoCAD 的 模 型 空 间 进 行 简 单 的 图 形 绘 制。
---- 有 了Application 和Document 对 象 实 例 的 句 柄 后, 就 可 以 对AutoCAD 进 行 图 形 绘 制 了。 在 此, 有 一 个 技 术 点, 即AutoCAD 模 型 空 间 点 的 定 义。
---- 在AutoCAD 的 模 型 空 间 中, 点 是 按 照 三 维 坐 标 进 行 定 义 的, 即 一 个 点 由 三 个 双 精 度 数 组 成 的 数 组 来 定 义。 但 由 于Delphi 是 通 过Automation 和AutoCAD 进 行 通 讯 的, 所 以 不 能 直 接 向AutoCAD 传 双 精 度 数。
---- 对 于 这 一 点, 可 以 通 过 在 程 序 中 生 成 双 精 度 的OleVariant 数 组 来 解 决, 如 下 所 示:
var
pnt_Start: OleVariant;
pnt_End: OleVariant;
......
begin
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_End:=VarArrayCreate([0,2],VT_R8);
---- VarArrayCreate 函 数 中 需 要 两 个 参 数, 第 一 个 是 需 生 成 的 数 组 的 维 数, 第 二 个 是 数 组 中 数 据 的 类 型, 常 量VT_R8 代 表8 字 节 的 实 型 数。 相 应 的 常 量 定 义 可 以 在 单 元ActiveX 中 找 到。
---- 下 面 是 用Delphi 在AutoCAD 模 型 空 间 里 画 一 个 圆 心 为(5.0,5.0,0), 半 径 为2.5 的 圆 的 例 子:
procedure TForm1.Button5Click(Sender: TObject);
var
obj_ModelSpace, obj_Acad:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0;
pnt_Start[1]:=5.0;
pnt_Start[2]:=0.0;
obj_ModelSpace.AddCircle
(VarArrayRef(pnt_Start), 2.5).Update;
end;
---- 在 上 面 的 程 序 中, 我 没 有 取ActiveDocument 的 实 例 句 柄, 而 是 直 接 取 了ModelSpace 的 实 例 句 柄。 在 生 成 一 个 三 维 的OleVariant 双 精 度 数 组 后, 对 它 进 行 赋 值, 然 后 调 用AddCircle 方 法 绘 制 一 个 圆, 并 让 它 立 即 显 示。
---- 在 程 序 的 最 后 第 二 行, 用 了AddCircle 方 法 来 绘 制 圆。 在 这 里 有 一 个 技 术 点, 即 如 何 把OleVariant 的 数 组 以 点 的 形 式 传 递 到AutoCAD.Application。 当 把 变 量pnt_Start 直 接 传 给AddCircle 方 法 时, 系 统 在 运 行 至 这 一 方 法 时 报 告 说 参 数 不 匹 配。 后 来 发 现 在AutoCAD 的Automation 服 务 器 中, 所 有 的 点 都 是 以 指 针 的 方 式 存 储 的, 把 变 量pnt_Start 传 给AddCircle 方 法 时, 必 须 以 指 针 方 式 传 变 量。 所 以 用VarArrayRef 函 数 进 行 转 换, 以 满 足 系 统 需 求。
---- 3、 获 取 和 设 置 系 统 变 量
---- 在AutoCAD 中, 有 很 多 的 系 统 变 量 用 来 作 为 绘 图 的 辅 助 设 置, 在AutoCAD Automation Server 里, 也 提 供 了 两 个 属 于ActiveDocument 的 方 法 来 进 行 读 取 和 设 置。 这 两 个 方 法 是:GetVariable 和SetVariable。 请 看 下 例:
procedure TForm1.Button5Click(Sender: TObject);
var
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0; pnt_Start[1]:=5.0; pnt_Start[2]:=0.0;
Edit5.Text:=obj_ActiveDoc.GetVariable('CECOLOR');
obj_ActiveDoc.SetVariable('CECOLOR','RED');
obj_ModelSpace.AddCircle(VarArrayRef(pnt_Start), 2.5).Update;
end;
---- 在 上 面 的 程 序 里, 我 从 当 前 活 动 的 文 档 中 取 得 当 前 的 颜 色 值, 把 它 送 到 一 个 编 辑 控 件 中 显 示 出 来, 然 后 再 把 当 前 的 颜 色 值 设 为 红 色, 并 用 当 前 颜 色 画 一 个 圆。
---- 4、 Delphi 处 理AutoCAD 中 的 中 文 文 本 显 示。
---- 中 文 文 本 的 显 示 一 直 是 在AutoCAD 制 图 中 的 一 个 重 要 问 题。AutoCAD 从R14 版 以 后 开 始 支 持Windows 的TrueType 字 体, 从 而 彻 底 解 决 了 这 个 问 题。
---- 用Delphi 处 理AutoCAD 中 的 中 文 文 本 显 示, 其 关 键 在 于 文 本 风 格 集(TextStyles) 的 设 置。 可 以 添 加 一 个 新 的 文 本 风 格(TextStyle), 然 后 把 该 文 本 风 格 的 字 体 设 为TrueType 中 文 字 体, 再 把 这 个 新 的 文 本 风 格 置 为 当 前 活 动 的 文 本 风 格, 即 可 在Delphi 里 对AutoCAD 发 命 令, 写 中 文 了。 请 看 下 例:
procedure TForm1.Button6Click(Sender: TObject);
var
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
obj_TextStyles:OleVariant;
obj_AcadUtility:OleVariant;
obj_TestStyle:OleVariant;
Ole_Point:OleVariant;
Ole_Height:OleVariant;
Ole_Text:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application.14');
except
obj_Acad:=CreateOleObject('AutoCad.Application.14');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:= obj_ActiveDoc.ModelSpace;
obj_TextStyles:=obj_ActiveDoc.TextStyles;
obj_AcadUtility:=obj_ActiveDoc.Utility;
obj_TestStyle:=obj_TextStyles.Add('TEST');
obj_TestStyle.FontFile:='simsun.ttf';
obj_ActiveDoc.activeTextStyle:=obj_TestStyle;
Ole_Point:=obj_AcadUtility.GetPoint
(,' 请输入文本的插入点:');
Ole_Height:=obj_AcadUtility.GetDistance
(Ole_Point,' 请输入文本的高度:');
Ole_Text:=obj_AcadUtility.GetString(1,' 请输入文本内容:');
obj_ModelSpace.AddText
(Ole_Text,VarArrayRef(Ole_Point),Ole_Height);
end;
---- 在 上 面 的 程 序 里, 我 用Utility 子 集 的 方 法GetPoint、GetDistance 和GetString 来 模 仿 通 常 在AutoCAD 绘 图 时 使 用 的Text 命 令, 并 用 模 型 空 间 子 集(ModelSpace) 的 方 法AddText 来 完 成 文 本 的 绘 制 工 作。
---- 5、 Delphi 处 理AutoCAD 中 的 选 择 集 问 题。
---- 在AutoCAD 绘 图 的 过 程 中, 经 常 遇 到 要 选 择 当 前 图 纸 中 的 某 些 已 有 的 图 形 进 行 操 作。 在AutoCAD.Application 中, 这 是 通 过 所 谓 选 择 集 子 集 来 完 成 的。 在 进 行 选 择 的 时 候, 可 以 通 过 选 择 集 子 集 来 生 成 一 个 新 的 选 择 集, 然 后 把 选 择 的 图 形 加 入 这 一 选 择 集 中, 这 样 便 可 以 通 过 选 择 集 来 处 理 选 择 的 图 形。 请 看 下 例:
procedure TForm1.Button1Click(Sender: TObject);
var
obj_Acad:OleVariant;
Line_Screen:OleVariant;
Line_Number:Integer;
SelectOne:OleVariant;
i:Integer;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
SelectOne:=obj_Acad.ActiveDocument.SelectionSets.Add('TEST');
SelectOne.SelectOnScreen;
Line_Number:=SelectOne.Count;
Line_Screen:=VarArrayCreate([0,Line_Number],varVariant);
for i:=0 to Line_Number-1 do
begin
Line_Screen:=SelectOne.Item(i);
end;
end;
在 上 面 的 程 序 里, 我 用SelectionSets 的Add 方 法 生 成 了 一 个 名 为TEST 的 选 择 集, 并 把 它 的 句 柄 赋 给 变 量SelectOne, 然 后 用SelectOne 的 方 法SelectOnScreen 在 屏 幕 上 进 行 选 择, 并 把 选 择 的 结 果 赋 给 变 量 数 组Line_Screen, 以 备 后 用。
---- 6、 块 问 题。
---- 在AutoCAD 绘 图 中, 块 的 操 作 是 一 种 十 分 有 效 的 绘 图 方 法。 在AutoCAD.Application 中, 也 完 全 支 持 块 的 处 理。 块 操 作 是 通 过Blocks 子 集 来 实 现 的。 生 成 块 的 时 候, 首 先 用Blocks 的Add 方 法 来 生 成 一 个 块, 然 后 就 可 以 用 类 似 在 模 型 空 间(ModelSpace) 中 绘 图 的 方 法 在 块 中 进 行 绘 制。 如 果 要 通 过 程 序 来 使 用 块, 只 要 用 模 型 空 间(ModelSpace) 的 方 法InsertBlock 就 可 以 把 块 插 入 模 型 空 间。 请 看 下 例:
procedure TForm1.Button7Click(Sender: TObject);
var
obj_BlockTest:OleVariant;
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0;
pnt_Start[1]:=5.0;
pnt_Start[2]:=0.0;
obj_BlockTest:=obj_ActiveDoc.
Blocks.Add(VarArrayRef(pnt_Start),'Test');
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 1).Update;
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 2).Update;
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 3).Update;
obj_ModelSpace.InsertBlock(VarArrayRef(pnt_Start),'Test',2,1,0);
end;
---- 在 上 面 的 程 序 里, 我 用Blocks 子 集 的Add 方 法 生 成 一 个 名 为Test 的 块, 并 把 块 的 插 入 点 设 置 为(5.0,5.0,0)。 然 后, 我 用AddCircle 方 法 在 块 中 生 成 三 个 通 信 圆。 最 后, 我 用 模 型 空 间(ModelSpace) 的 方 法InsertBlock 把Test 块 插 入 到(5.0,5.0,0) 的 位 置, 插 入 比 例 为X 轴 方 向 放 大 一 倍,Y 轴 方 向 保 持 不 变, 图 形 旋 转 零 度。
希望有用delphi进行cad二次开发的富翁们做一点贡献,在CAD领域发挥光大delphi!
现我将在网上找到的资料整理出来:
1、Delphi 在AutoCAD 二 次 开 发 中 的 应 用
一、 引 言
---- AutoCAD 是 世 界 上 使 用 范 围 最 广 的CAD 系 统, 基 于 其 之 上 的 二 次 开 发 一 直 有 很 大 的 市 场 需 求。 最 初, 这 些 二 次 开 发 只 能 使 用AutoLISP 进 行, 这 是 一 种 解 释 型 的 编 程 语 言, 执 行 效 率 较 低, 而 且 稳 定 性 较 差。 从R11.0 版 以 后,AutoCAD 推 出 了ADS 接 口, 支 持 用C 语 言 进 行 开 发。 到R13 版 后, 又 推 出 了ARX 接 口, 支 持C++ 语 言。 但 这 两 种 接 口 的 程 序 设 计 都 较 为 繁 琐, 不 利 于 推 广。 从R14 版 开 始,AutoCAD 开 始 支 持ActiveX Automation 技 术, 这 一 方 面 提 供 了 一 种 安 全 而 稳 定 的 二 次 开 发 接 口, 另 一 方 面 又 大 大 简 化 了 程 序 设 计 的 工 作, 使 基 于AutoCAD 的 二 次 开 发 进 入 了 一 个 新 的 阶 段。
---- ActiveX Automation 是 一 种 专 用 于 使Windows 下 应 用 程 序 相 互 联 系 的 技 术, 其 前 身 是OLE Automation 技 术。ActiveX Automation 分 为 两 层:Automation Server 和Automation Controller。
---- Automation Server 是 一 种 应 用 程 序, 它 把 自 身 或 自 身 的 一 部 分 进 行 打 包 后, 作 为 一 个 完 整 的 对 象 输 出。 当 它 第 一 次 运 行 时, 它 会 在 系 统 的 注 册 表 中 写 入 注 册 信 息, 包 括 对 象 的 注 册 名、 注 册 号 和 完 整 的 执 行 路 径。 有 了 这 些 注 册 信 息 后,Automation Controller 应 用 程 序 就 可 以 按 照 对 象 的 注 册 名 向 系 统 申 请。 如 果 申 请 得 到 认 可, 系 统 就 会 生 成 一 个 该 对 象 的 实 例, 并 把 该 实 例 的 句 柄 传 给Automation Controller 应 用 程 序。 通 过 这 个 句 柄,Automation Controller 应 用 程 序 就 可 以 使 用 该 对 象 实 例 提 供 的 全 部 功 能 了。ActiveX Automation 是 完 全 独 立 于 语 言 的 技 术, 也 就 是 说, 可 以 用 任 何 一 种 程 序 设 计 语 言 来 开 发Automation Server 和Automation Controller 应 用 程 序。
---- AutoCAD 从R14 版 开 始 引 入 了Automation 技 术, 它 把 全 部 的 系 统 功 能 和 函 数 打 包 成 为 一 个 名 为AutoCAD.Application.14 的Automation Server 对 象。 通 过 这 个 对 象, 应 用 程 序 可 以 访 问AutoCAD 的 全 部 功 能。
二、 AutoCAD ActiveX Automation 对 象 体 系 结 构
---- AutoCAD ActiveX Automation 对 象 体 系 结 构 如 下 页 图 所 示。 在 对 象 模 型 中, 处 于 最 高 层 的 对 象 是AutoCAD.Application, 称 为 应 用 对 象, 它 包 含 了AutoCAD ActiveX Automation 对 象 所 提 供 的 全 部 功 能。
---- 在AutoCAD.Application 层 之 下 是Preferences 和Document 子 对 象。Preferences 子 对 象 等 价 于AutoCAD 的Preferences 对 话 框, 它 包 含 了AutoCAD 的 当 前 的 系 统 参 数 设 置。Document 子 对 象 代 表AutoCAD 系 统 中 当 前 活 动 的 图 纸 文 件, 通 过Document 子 对 象 可 以 对 系 统 中 当 前 活 动 的 图 纸 文 件 进 行 所 有 的 处 理。
---- Document 子 对 象 包 含 了 所 有 的 图 纸 信 息 子 层, 有: 模 型 空 间 子 集(ModelSpaceEntities Collection)、 纸 空 间 子 集(PaperSpaceEntities Collection) 和 块 子 集(Blocks Collection) 包 含 所 有 的 三 维 图 形 绘 制 对 象, 用 来 进 行 图 形 文 件 的 绘 制; 字 典 子 集(Dictionaries Collection) 负 责 自 动 拼 写 检 查; 标 注 子 集(DimStyles Collection) 负 责 图 纸 标 注; 组 子 集(Groups Collection) 负 责 当 前 活 动 的 图 纸 文 件 中 所 有 的 组 的 管 理; 层 子 集(Layers Collection) 负 责 当 前 活 动 的 图 纸 文 件 中 层 的 设 置; 线 型 子 集(Linetypes Collection) 管 理 线 型; 已 注 册 应 用 程 序 子 集(RegisteredApp Collection) 管 理 系 统 中 的 外 加 应 用 程 序; 选 择 组 子 集(SellectionSets Collection) 管 理 用 户 在 图 纸 中 所 选 择 的 内 容; 文 本 风 格 子 集(TextStyles Collection) 负 责 文 本 字 符 风 格; 用 户 坐 标 系 子 集(UCSs Collection) 负 责 管 理 用 户 坐 标 系; 视 图 子 集(Views Collection) 负 责 管 理 用 户 视 图; 视 角 子 集(Viewports Collection) 负 责 视 角 转 换 控 制; 打 印 输 出 子 集(Plot) 负 责 控 制 图 形 文 件 的 最 终 输 出 及 打 印 设 置; 应 用 子 集(Utility) 包 含 了 大 量 的 辅 助 函 数, 用 来 进 行 辅 助 计 算。
三、 用Delphi 3 进 行AutoCAD 二 次 开 发
---- 在AutoCAD R14 版 的 在 线 帮 助 中, 对 于AutoCAD ActiveX Automation 的 使 用 有 完 整 的 说 明, 并 有 不 少 例 子, 但 都 是 通 过Visual Basic 来 实 现 的。 考 虑 到ActiveX Automation 的 语 言 独 立 性, 完 全 可 以 用Delphi 来 很 好 的 实 现 它。 下 面 我 就 在 实 现 过 程 中 的 一 些 问 题 谈 谈 个 人 的 体 会。
---- 1、 获 取AutoCAD 的Application 和Document 对 象 的 实 例。
---- 获 取AutoCAD 的Application 和Document 对 象 的 实 例 是 对AutoCAD 进 行Automation 开 发 的 基 础。 在VB 中, 可 以 通 过CreateObject 和GetObject 两 个 函 数 来 取 得 实 例 句 柄, 而 在Delphi 中, 相 应 的 函 数 就 变 为CreateOleObject 和GetActiveOleObject。 请 看 下 面 的 程 序:
procedure TForm1.FormCreate(Sender: TObject);
var
obj_Acad ,obj_Doc: OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application.14');
except
obj_Acad:=CreateOleObject('AutoCAD.Application.14');
end;
obj_Acad.Visible:=True;
obj_Doc:=obj_Acad.ActiveDocument;
end;
---- 在 上 面 的 程 序 段 中, 在 第 三 行 定 义 了 两 个 变 量, 分 别 为obj_Doc 和obj_Acad, 变 量 类 型 为OleVariant。OleVariant 是Delphi 为 提 供 完 全OLE 支 持 而 提 供 的 一 种 特 殊 的 数 据 类 型, 可 以 用 它 来 存 储 任 何 类 型 的 数 据。 但 大 量 的 使 用OleVariant 会 大 大 影 响 程 序 的 运 行 速 度, 故 此 只 有 在 必 要 时 才 使 用 它。
---- 从 第 五 行 开 始 连 接AutoCAD.Application。 首 先, 用 函 数GetActiveOleObject 来 读 取 一 个AutoCAD.Application 的 实 例。 当AutoCAD 有 实 例 处 于 运 行 状 态 时, 这 个 函 数 会 取 到 当 前 运 行 的AutoCAD 的 实 例 句 柄, 并 把 它 赋 值 给obj_Acad; 而 当AutoCAD 没 有 实 例 处 于 运 行 状 态 时, 这 个 函 数 会 抛 出 一 个 异 常。 此 时, 程 序 自 动 进 入except 开 头 的 异 常 处 理 模 块。
---- 在 异 常 模 块 里, 程 序 用 函 数CreateOleObject 生 成 一 个AutoCAD.Application 的 实 例, 并 把 它 的 实 例 句 柄 赋 值 给obj_Acad, 从 而 完 成 与AutoCAD.Application 连 接 的 过 程。
---- 接 下 来, 利 用AutoCAD.Application 的Visible 属 性 把AutoCAD 的 窗 口 显 示 出 来。 然 后, 把 活 动 文 档 的 对 象 句 柄 赋 值 给 变 量obj_Doc。 这 样, 就 完 成 了Application 和Document 对 象 实 例 的 获 取。
---- 另 外, 为 了 支 持OleVariant 数 据 类 型, 必 须 在Delphi 的 单 元 中(Unit) 引 入comObj 单 元 和ActiveX 单 元。
---- 2、 用Delphi 在AutoCAD 的 模 型 空 间 进 行 简 单 的 图 形 绘 制。
---- 有 了Application 和Document 对 象 实 例 的 句 柄 后, 就 可 以 对AutoCAD 进 行 图 形 绘 制 了。 在 此, 有 一 个 技 术 点, 即AutoCAD 模 型 空 间 点 的 定 义。
---- 在AutoCAD 的 模 型 空 间 中, 点 是 按 照 三 维 坐 标 进 行 定 义 的, 即 一 个 点 由 三 个 双 精 度 数 组 成 的 数 组 来 定 义。 但 由 于Delphi 是 通 过Automation 和AutoCAD 进 行 通 讯 的, 所 以 不 能 直 接 向AutoCAD 传 双 精 度 数。
---- 对 于 这 一 点, 可 以 通 过 在 程 序 中 生 成 双 精 度 的OleVariant 数 组 来 解 决, 如 下 所 示:
var
pnt_Start: OleVariant;
pnt_End: OleVariant;
......
begin
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_End:=VarArrayCreate([0,2],VT_R8);
---- VarArrayCreate 函 数 中 需 要 两 个 参 数, 第 一 个 是 需 生 成 的 数 组 的 维 数, 第 二 个 是 数 组 中 数 据 的 类 型, 常 量VT_R8 代 表8 字 节 的 实 型 数。 相 应 的 常 量 定 义 可 以 在 单 元ActiveX 中 找 到。
---- 下 面 是 用Delphi 在AutoCAD 模 型 空 间 里 画 一 个 圆 心 为(5.0,5.0,0), 半 径 为2.5 的 圆 的 例 子:
procedure TForm1.Button5Click(Sender: TObject);
var
obj_ModelSpace, obj_Acad:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0;
pnt_Start[1]:=5.0;
pnt_Start[2]:=0.0;
obj_ModelSpace.AddCircle
(VarArrayRef(pnt_Start), 2.5).Update;
end;
---- 在 上 面 的 程 序 中, 我 没 有 取ActiveDocument 的 实 例 句 柄, 而 是 直 接 取 了ModelSpace 的 实 例 句 柄。 在 生 成 一 个 三 维 的OleVariant 双 精 度 数 组 后, 对 它 进 行 赋 值, 然 后 调 用AddCircle 方 法 绘 制 一 个 圆, 并 让 它 立 即 显 示。
---- 在 程 序 的 最 后 第 二 行, 用 了AddCircle 方 法 来 绘 制 圆。 在 这 里 有 一 个 技 术 点, 即 如 何 把OleVariant 的 数 组 以 点 的 形 式 传 递 到AutoCAD.Application。 当 把 变 量pnt_Start 直 接 传 给AddCircle 方 法 时, 系 统 在 运 行 至 这 一 方 法 时 报 告 说 参 数 不 匹 配。 后 来 发 现 在AutoCAD 的Automation 服 务 器 中, 所 有 的 点 都 是 以 指 针 的 方 式 存 储 的, 把 变 量pnt_Start 传 给AddCircle 方 法 时, 必 须 以 指 针 方 式 传 变 量。 所 以 用VarArrayRef 函 数 进 行 转 换, 以 满 足 系 统 需 求。
---- 3、 获 取 和 设 置 系 统 变 量
---- 在AutoCAD 中, 有 很 多 的 系 统 变 量 用 来 作 为 绘 图 的 辅 助 设 置, 在AutoCAD Automation Server 里, 也 提 供 了 两 个 属 于ActiveDocument 的 方 法 来 进 行 读 取 和 设 置。 这 两 个 方 法 是:GetVariable 和SetVariable。 请 看 下 例:
procedure TForm1.Button5Click(Sender: TObject);
var
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0; pnt_Start[1]:=5.0; pnt_Start[2]:=0.0;
Edit5.Text:=obj_ActiveDoc.GetVariable('CECOLOR');
obj_ActiveDoc.SetVariable('CECOLOR','RED');
obj_ModelSpace.AddCircle(VarArrayRef(pnt_Start), 2.5).Update;
end;
---- 在 上 面 的 程 序 里, 我 从 当 前 活 动 的 文 档 中 取 得 当 前 的 颜 色 值, 把 它 送 到 一 个 编 辑 控 件 中 显 示 出 来, 然 后 再 把 当 前 的 颜 色 值 设 为 红 色, 并 用 当 前 颜 色 画 一 个 圆。
---- 4、 Delphi 处 理AutoCAD 中 的 中 文 文 本 显 示。
---- 中 文 文 本 的 显 示 一 直 是 在AutoCAD 制 图 中 的 一 个 重 要 问 题。AutoCAD 从R14 版 以 后 开 始 支 持Windows 的TrueType 字 体, 从 而 彻 底 解 决 了 这 个 问 题。
---- 用Delphi 处 理AutoCAD 中 的 中 文 文 本 显 示, 其 关 键 在 于 文 本 风 格 集(TextStyles) 的 设 置。 可 以 添 加 一 个 新 的 文 本 风 格(TextStyle), 然 后 把 该 文 本 风 格 的 字 体 设 为TrueType 中 文 字 体, 再 把 这 个 新 的 文 本 风 格 置 为 当 前 活 动 的 文 本 风 格, 即 可 在Delphi 里 对AutoCAD 发 命 令, 写 中 文 了。 请 看 下 例:
procedure TForm1.Button6Click(Sender: TObject);
var
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
obj_TextStyles:OleVariant;
obj_AcadUtility:OleVariant;
obj_TestStyle:OleVariant;
Ole_Point:OleVariant;
Ole_Height:OleVariant;
Ole_Text:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application.14');
except
obj_Acad:=CreateOleObject('AutoCad.Application.14');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:= obj_ActiveDoc.ModelSpace;
obj_TextStyles:=obj_ActiveDoc.TextStyles;
obj_AcadUtility:=obj_ActiveDoc.Utility;
obj_TestStyle:=obj_TextStyles.Add('TEST');
obj_TestStyle.FontFile:='simsun.ttf';
obj_ActiveDoc.activeTextStyle:=obj_TestStyle;
Ole_Point:=obj_AcadUtility.GetPoint
(,' 请输入文本的插入点:');
Ole_Height:=obj_AcadUtility.GetDistance
(Ole_Point,' 请输入文本的高度:');
Ole_Text:=obj_AcadUtility.GetString(1,' 请输入文本内容:');
obj_ModelSpace.AddText
(Ole_Text,VarArrayRef(Ole_Point),Ole_Height);
end;
---- 在 上 面 的 程 序 里, 我 用Utility 子 集 的 方 法GetPoint、GetDistance 和GetString 来 模 仿 通 常 在AutoCAD 绘 图 时 使 用 的Text 命 令, 并 用 模 型 空 间 子 集(ModelSpace) 的 方 法AddText 来 完 成 文 本 的 绘 制 工 作。
---- 5、 Delphi 处 理AutoCAD 中 的 选 择 集 问 题。
---- 在AutoCAD 绘 图 的 过 程 中, 经 常 遇 到 要 选 择 当 前 图 纸 中 的 某 些 已 有 的 图 形 进 行 操 作。 在AutoCAD.Application 中, 这 是 通 过 所 谓 选 择 集 子 集 来 完 成 的。 在 进 行 选 择 的 时 候, 可 以 通 过 选 择 集 子 集 来 生 成 一 个 新 的 选 择 集, 然 后 把 选 择 的 图 形 加 入 这 一 选 择 集 中, 这 样 便 可 以 通 过 选 择 集 来 处 理 选 择 的 图 形。 请 看 下 例:
procedure TForm1.Button1Click(Sender: TObject);
var
obj_Acad:OleVariant;
Line_Screen:OleVariant;
Line_Number:Integer;
SelectOne:OleVariant;
i:Integer;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
SelectOne:=obj_Acad.ActiveDocument.SelectionSets.Add('TEST');
SelectOne.SelectOnScreen;
Line_Number:=SelectOne.Count;
Line_Screen:=VarArrayCreate([0,Line_Number],varVariant);
for i:=0 to Line_Number-1 do
begin
Line_Screen:=SelectOne.Item(i);
end;
end;
在 上 面 的 程 序 里, 我 用SelectionSets 的Add 方 法 生 成 了 一 个 名 为TEST 的 选 择 集, 并 把 它 的 句 柄 赋 给 变 量SelectOne, 然 后 用SelectOne 的 方 法SelectOnScreen 在 屏 幕 上 进 行 选 择, 并 把 选 择 的 结 果 赋 给 变 量 数 组Line_Screen, 以 备 后 用。
---- 6、 块 问 题。
---- 在AutoCAD 绘 图 中, 块 的 操 作 是 一 种 十 分 有 效 的 绘 图 方 法。 在AutoCAD.Application 中, 也 完 全 支 持 块 的 处 理。 块 操 作 是 通 过Blocks 子 集 来 实 现 的。 生 成 块 的 时 候, 首 先 用Blocks 的Add 方 法 来 生 成 一 个 块, 然 后 就 可 以 用 类 似 在 模 型 空 间(ModelSpace) 中 绘 图 的 方 法 在 块 中 进 行 绘 制。 如 果 要 通 过 程 序 来 使 用 块, 只 要 用 模 型 空 间(ModelSpace) 的 方 法InsertBlock 就 可 以 把 块 插 入 模 型 空 间。 请 看 下 例:
procedure TForm1.Button7Click(Sender: TObject);
var
obj_BlockTest:OleVariant;
obj_ModelSpace:OleVariant;
obj_Acad:OleVariant;
obj_ActiveDoc:OleVariant;
pnt_Start:OleVariant;
begin
try
obj_Acad:=GetActiveOleObject('AutoCAD.Application');
except
obj_Acad:=CreateOleObject('AutoCad.Application');
end;
obj_Acad.visible:=True;
obj_ActiveDoc:=obj_Acad.ActiveDocument;
obj_ModelSpace:=obj_Acad.ActiveDocument.ModelSpace;
pnt_Start:=VarArrayCreate([0,2],VT_R8);
pnt_Start[0]:=5.0;
pnt_Start[1]:=5.0;
pnt_Start[2]:=0.0;
obj_BlockTest:=obj_ActiveDoc.
Blocks.Add(VarArrayRef(pnt_Start),'Test');
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 1).Update;
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 2).Update;
obj_BlockTest.AddCircle(VarArrayRef(pnt_Start), 3).Update;
obj_ModelSpace.InsertBlock(VarArrayRef(pnt_Start),'Test',2,1,0);
end;
---- 在 上 面 的 程 序 里, 我 用Blocks 子 集 的Add 方 法 生 成 一 个 名 为Test 的 块, 并 把 块 的 插 入 点 设 置 为(5.0,5.0,0)。 然 后, 我 用AddCircle 方 法 在 块 中 生 成 三 个 通 信 圆。 最 后, 我 用 模 型 空 间(ModelSpace) 的 方 法InsertBlock 把Test 块 插 入 到(5.0,5.0,0) 的 位 置, 插 入 比 例 为X 轴 方 向 放 大 一 倍,Y 轴 方 向 保 持 不 变, 图 形 旋 转 零 度。