之前聊了 MxCAD 的内置命令和圆弧、多段线的绘制,图有了,接下来就是怎么选中它们。对象选择其实就两件事:一是光标底下到底是哪个对象,二是怎么把一批对象挑出来统一处理。
在 MxCAD 里,选择分两条路走:一条靠 UI 交互,点选、框选、累加都行;另一条纯代码驱动,比如全选、按 ID 或句柄直接找、按特征筛选。不管走哪条路,都能挂上同一套筛选条件,把范围锁定在特定类型或图层上。

无论用哪种方式选择对象,最终拿到的都是一个
McObjectId(对象 ID)。它本身不携带实体的几何数据,只描述"这是数据库里的哪一个对象"。要真正操作实体,需要通过
getMcDbEntity() 从 ID 取出实体实例:
import {
MxCADUiPrEntity }
from
"mxcad";
const
getEnt
=
new
MxCADUiPrEntity();
getEnt.
setMessage(
"请选择目标对象");
const
entId
=
await
getEnt.
go();
if (
!entId
||
!entId.
id)
return;
const
ent
=
entId.
getMcDbEntity();
if (
ent)
console.
log(
"对象类型:",
ent.
objectName);
McObjectId 还提供了几个常用判断方法:
entId.
isValid();
// ID 是否有效
entId.
isNull();
// ID 是否为空
entId.
isKindOf(
"McDbLine");
// 指向的对象是否为直线
entId.
isErase();
// 指向的对象是否已被删除
后续所有选择方式,都可以理解为"得到一个或一组
McObjectId",再通过
getMcDbEntity() 拿到实体做下一步操作。
MxCADResbuf 用来描述"哪些对象有资格被选中"。它可以挂载实体类型、图层、颜色、块名等条件,同时适用于有 UI 交互的选择和没有 UI 交互的选择。
import {
MxCADResbuf }
from
"mxcad";
const
filter
=
new
MxCADResbuf();
filter.
AddMcDbEntityTypes(
"LINE,CIRCLE");
// 只允许选直线和圆
后文每种选择方式都会用到这个筛选条件,这里先建立概念,具体用法在第五节展开。
有 UI 交互的选择都需要用户参与(或给定坐标),返回一个选择集或对象 ID,并且可以挂
MxCADResbuf 过滤。
MxCADUiPrEntity
用于让用户在图纸上点选
一个对象,返回对应的
McObjectId,适合"选中某个对象后继续操作"的场景,如编辑、附加属性、读取属性等。
import {
MxCADUiPrEntity }
from
"mxcad";
const
getEnt
=
new
MxCADUiPrEntity();
getEnt.
setMessage(
"请选择目标对象");
const
entId
=
await
getEnt.
go();
if (
!entId
||
!entId.
id)
return;
const
ent
=
entId.
getMcDbEntity();
if (
ent)
console.
log(
"当前对象类型:",
ent.
objectName);
点选结束后,还可以拿到"点在哪里选的"这个坐标,以及区分用户是选中了对象、按了回车还是输入了关键字:
const
pickPt
=
getEnt.
pickPoint();
// 拾取时的图纸坐标
const
status
=
getEnt.
getStatus();
// 操作状态
if (
getEnt.
isKeyWordPicked(
"P")) {
// 用户输入了关键字 P(如"上一个对象")
}
如果坐标已经确定,不需要用户交互,可以直接用坐标在该处点选对象:
import {
MxCADSelectionSet,
MxCADResbuf }
from
"mxcad";
const
ss
=
new
MxCADSelectionSet();
const
filter
=
new
MxCADResbuf();
filter.
AddMcDbEntityTypes(
"TEXT,MTEXT");
// 只挑文字对象
const
index
=
ss.
pointSelect(
point.
x,
point.
y,
filter);
const
ent
=
ss.
item(
index).
getMcDbEntity();
pointSelect 的第三个参数是筛选条件,第四个参数是拾取容差。
如果不走选择集,
MxCADUtility.findEntAtPoint() 可以直接在某点取到命中的实体,返回一个
McObjectId,适合"点选即识别"的场景:
import {
MxCADUtility,
MxCADResbuf,
DxfCode }
from
"mxcad";
// 在 (x, y, z) 处查找命中的对象,-1 表示用默认拾取范围
const
objId
=
MxCADUtility.
findEntAtPoint(
x,
y,
z,
-1,
null);
if (
objId.
isValid()) {
const
ent
=
objId.
getMcDbEntity();
console.
log(
"命中对象:",
ent?.
objectName);
}
// 也可以带筛选条件,只命中直线
const
filter
=
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE"]);
const
lineId
=
MxCADUtility.
findEntAtPoint(
x,
y,
z,
-1,
filter);
userSelect 让用户在图纸上拉框选择,最接近桌面 CAD 中直接框选的操作:
import {
MxCADSelectionSet,
MxCADResbuf }
from
"mxcad";
const
ss
=
new
MxCADSelectionSet();
const
filter
=
new
MxCADResbuf();
filter.
AddMcDbEntityTypes(
"INSERT");
// 只选块参照
if (
await
ss.
userSelect(
"选择要刷的目标块:",
filter)) {
const
ids
=
ss.
getIds();
// 拿到全部选中的对象 ID
}
userSelect
返回一个布尔值,表示用户是否确认了选择:
true 表示选中并确认,
false 表示用户取消(按 Esc)或直接回车退出。
const
confirmed
=
await
ss.
userSelect(
"选择要刷的目标块:",
filter);
if (
confirmed) {
// 用户确认选择:处理 ss 中已选中的对象
}
else {
// 用户取消或退出
}
如果需要更细地区分结束原因,可以参考
MxCADSelectionSetStatus 枚举:
kSelected(构造成功)、
kNone(直接回车)、
kCanceled(按 Esc 取消)、
kRejected(无效关键字)、
kKeyword(输入了关键字)。
框选完成后,可以调用
getSelectPoint() 取回框选的两个对角点
{pt1, pt2},也可以调用
getSelectPoints() 取回整条选择框的点阵。
const {
pt1,
pt2}
=
ss.
getSelectPoint();
const
points
=
ss.
getSelectPoints();
如果两个对角点已经确定,可以用
crossingSelect 直接完成框选,不需要用户交互:
ss.crossingSelect(x1, y1, x2, y2, filter);
交叉窗选对应 AutoCAD 中的"交叉 C":框内对象和跨越框边界的对象都会被选中。这与"窗选 W"(只选完全在框内的对象)不同。
栅栏选对应 AutoCAD 的
F:用户画一条折线栅栏,选中所有被栅栏穿过的对象:
if (
await
ss.
fenceSelect(
"选择栅栏要穿过的对象:",
filter)) {
console.
log(
"栅栏选中:",
ss.
count());
}
MxCADSelectionSet
默认
isWhileSelect = true,即循环选择:用户可以多次点选或框选,每次选择都累加进同一个选择集,直到确认结束。
const
ss
=
new
MxCADSelectionSet();
ss.
isWhileSelect
=
true;
// 循环选择:多次选择不断累加
ss.
isSelectHighlight
=
true;
// 选中对象高亮显示
// 用户连续点选,每次都往 ss 里累加;结束后:
const
ids
=
ss.
getIds();
console.
log(
"累计选中:",
ss.
count());
currentSelect(filter?) 用于读取当前已选中的对象(对应 AutoCAD 的 PICKFIRST 语义),返回当前已选对象的数量:
// 读取当前已选对象数量
const
n
=
ss.
currentSelect();
// 带条件:只统计直线
const
lineCount
=
ss.
currentSelect(
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE"]));
isFilterLockLayer 是一个布尔开关,控制遍历时是否跳过锁定图层上的对象,默认不跳过:
ss.isFilterLockLayer = true; // 遍历时跳过锁定图层上的对象
无 UI 交互的选择不依赖用户操作,由代码直接驱动,适合脚本、批处理和自动化场景。
const
ss
=
new
MxCADSelectionSet();
ss.
allSelect();
// 全选当前空间的所有对象
也可以带条件,只选特定类型、特定图层上的对象:
import {
DxfCode }
from
"mxcad";
// 只选 0 层上的直线、圆弧、圆、多段线
ss.
allSelect(
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE,ARC,CIRCLE,LWPOLYLINE",
DxfCode.
kLayer,
"0"
]));
console.
log(
"对象数:",
ss.
count());
McObjectId 的构造函数接受一个对象 ID(number 类型),可以直接由已知的 ID 还原出实体:
import {
McObjectId }
from
"mxcad";
const
id
=
new
McObjectId(
knownId);
if (
id.
isValid()
&&
!id.
isNull()) {
const
ent
=
id.
getMcDbEntity();
console.
log(
ent?.
objectName);
}
这是选择结果与后续操作之间的衔接方式:
drawEntity、
allSelect、
getIds() 等返回的都是
McObjectId,链式调用
getMcDbEntity() 即可继续编辑。
句柄(handle)是对象在数据库中的字符串标识。数据库提供"句柄 → ID"的反查方法:
import {
MxCpp }
from
"mxcad";
const
db
=
MxCpp.
getCurrentMxCAD().
getDatabase();
const
id
=
db.
handleToIdIndex(
"ABCD1234");
// 句柄 → McObjectId
if (
id
&&
id.
isValid()) {
const
ent
=
id.
getMcDbEntity();
console.
log(
"句柄对应实体:",
ent?.
objectName);
}
反向操作是实体侧的
getHandle(),用于从实体取出句柄。ID、句柄、实体三者可以互相转换。
按实体特征查找,就是按对象自身的属性把符合条件的对象挑出来。根据特征的类型,有三种由浅入深的方式。
allSelect
配合
MxCADResbuf,用
DxfCode 指定特征维度,可以直接筛选类型、图层、颜色、块名等:
// 找 0 层上、颜色为 1、类型为直线的对象
ss.
allSelect(
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE",
DxfCode.
kLayer,
"0",
DxfCode.
kColor,
1
]));
条件筛选只能覆盖类型、图层、颜色、块名这类表级特征。如果要按几何量(半径、长度、坐标)识别对象,需要全选后遍历,逐个读取实体属性做判断:
ss.
allSelect(
new
MxCADResbuf([
DxfCode.
kEntityType,
"CIRCLE"]));
ss.
forEach((
id)
=> {
const
circle
=
id.
getMcDbEntity();
if (
circle
&&
Math.
abs(
circle.
radius
-
50)
<
1e-6) {
console.
log(
"找到半径约 50 的圆:",
circle.
objectName);
}
});
按空间边界(点集围成的区域)筛选对象,典型用途是块参照的边界裁剪:
const
spatialFilter
=
blkRef.
getSpatialFilterId().
getMcDbObject();
spatialFilter.
setBoundary(
aryPoint);
// 设置剪切边界点集
spatialFilter.
setEnable(
true);
无论用哪种方式选择,选中的对象都存放在
MxCADSelectionSet 中,通过以下方法读取:
ss.
count();
// 选中对象数量
ss.
item(
i);
// 按索引取第 i 个对象的 McObjectId
ss.
getIds();
// 取全部选中对象的 McObjectId 数组
ss.
forEach((
id)
=> {
// 遍历每个选中对象
const
ent
=
id.
getMcDbEntity();
});
ss.
clear();
// 清空选择集
ss.
isNull();
// 判断选择集是否为空
前面每种选择方式都能挂上
MxCADResbuf,这是筛选贯穿两种选择方式的关键。
import {
MxCADResbuf,
DxfCode }
from
"mxcad";
// 方式一:链式 add
const
f1
=
new
MxCADResbuf();
f1.
AddMcDbEntityTypes(
"LINE,CIRCLE");
// 方式二:构造时直接给「组码, 值」对
const
f2
=
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE,ARC",
DxfCode.
kLayer,
"0"
]);
DxfCode 枚举定义了筛选时可用的特征维度:
| 组码 | 含义 | 组码 | 含义 |
|---|---|---|---|
kEntityType |
实体类型 |
kLayer |
图层 |
kColor |
颜色 |
kBlockName |
块名 |
kExDataName |
扩展数据名 |
kAppName |
XData 类型 |
实体类型值域包括:
LINE、
ARC、
CIRCLE、
LWPOLYLINE、
TEXT、
MTEXT、
INSERT、
ELLIPSE、
SPLINE、
POINT、
LinkLine。
同一个
MxCADResbuf 实例,既可以挂到有 UI 交互的选择上,也可以挂到无 UI 交互的选择上:
const
filter
=
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE"]);
// 交互侧
const
getEnt
=
new
MxCADUiPrEntity();
getEnt.
setFilter(
filter);
// 点选时只允许选直线
const
ss
=
new
MxCADSelectionSet();
ss.
userSelect(
"选择直线:",
filter);
// 框选时只选直线
ss.
allSelect(
filter);
// 程序化全选时也只选直线
MxCADResbuf 也能反向读出其中的条件,便于调试或复用:
filter.
GetCount();
// 条件项数量
filter.
AtString(
0);
// 取第 0 项字符串
filter.
AtDouble(
1);
// 取第 1 项 double
filter.
AtPoint(
2);
// 取第 2 项点坐标
filter.
AtObjectId(
3);
// 取第 3 项对象 ID
选择只是第一步,选中对象后要做的是编辑、改属性、删除等。下面是一个"选择 → 批量改属性"的完整小命令,展示选完之后的用法:
import {
MxCADSelectionSet,
MxCADResbuf,
DxfCode }
from
"mxcad";
async
function
Mx_SelectAndSetLinetype() {
const
ss
=
new
MxCADSelectionSet();
const
filter
=
new
MxCADResbuf([
DxfCode.
kEntityType,
"LINE"]);
if (
!await
ss.
userSelect(
"选择要改线型的直线:",
filter))
return;
ss.
forEach((
id)
=> {
const
ent
=
id.
getMcDbEntity();
if (
ent)
ent.
linetype
=
"DASHED";
// 批量改线型
});
}
对象选择是"用户意图"与"对象数据库"之间的环节,也是所有编辑命令的前置步骤。MxCAD 中对象选择分两类:
有 UI 交互:点选(
MxCADUiPrEntity /
pointSelect)、框选(
userSelect /
crossingSelect /
fenceSelect)、累加选择(
isWhileSelect)。
无 UI 交互:全选(
allSelect)、按已知 ID 查找(
new McObjectId)、按已知句柄查找(
handleToIdIndex)、按实体特征查找(条件筛选 / 属性遍历 /
McDbSpatialFilter)。
两类选择共用同一套筛选条件
MxCADResbuf,通过
DxfCode 指定类型、图层、颜色、块名等特征维度。选中的对象统一存放在
MxCADSelectionSet 中,通过
count、
item、
getIds、
forEach 读取,再对每个
McObjectId 调用
getMcDbEntity() 拿到实体实例做后续操作。
掌握对象选择后,就可以进入修改工具,把选中的对象真正移动、复制、旋转编辑起来。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70041755/viewspace-3185864/ ,如需转载,请注明出处,否则将追究法律责任。