command-events
本文回答:枚举里有 4 个命令事件,但实际派发的只有 3 个:
CommandStarting(前,可取消)/CommandStarted(后)/CommandEnded(结束,args{commandName, success, duration})。CommandCancelled是未派发的保留事件——按 ESC 退出命令同样触发CommandEnded(success=false仅表示main()抛了异常),"是否被取消"需由命令自身判断。常用于操作日志、自动化、命令钩子。
一、事件清单
| 事件 | 说明 | 可取消 |
|---|---|---|
CommandStarting |
命令开始前 | 是 |
CommandStarted |
命令开始后 | 否 |
CommandEnded |
命令结束(正常完成、ESC 退出、main() 抛异常都触发;success=false 仅表示抛了异常) |
否 |
CommandCancelled |
✗ 未派发(枚举保留成员,订阅永不触发) | — |
MCP 参考:vjcad/doc/event/event-types.md;派发点在 invokeCommandWithOp(只 emit Starting/Started/Ended)。
二、最小用法
import { Engine, CadEvents } from 'vjcad';
Engine.eventManager.on(CadEvents.CommandStarted, (args) => {
console.log('命令开始:', args.commandName);
});
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
// ESC 取消也走这里;success 只区分 main() 是否抛异常
console.log('命令结束:', args.commandName, args.success, args.duration + 'ms');
});
MCP 参考:vjcad/example/event/04commandevents.js、vjcad/doc/event/event-usage.md。
三、操作日志
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
log(`用户执行了命令: ${args.commandName}`, new Date());
});
四、阻止特定命令
const blocked = new Set(['EXPORTDWG', 'PURGE']);
Engine.eventManager.on(CadEvents.CommandStarting, (args) => {
if (blocked.has(args.commandName)) {
args.cancel = true;
alert(`命令 ${args.commandName} 已被禁用`);
}
});
MCP 参考:vjcad/doc/event/event-usage.md。
五、配合 PLINE / SPLINE 等交互式命令
let activePline = null;
Engine.eventManager.on(CadEvents.CommandStarted, (args) => {
if (args.commandName === 'PLINE') activePline = null;
});
Engine.eventManager.on(CadEvents.EntityAdded, (args) => {
if (args.entity.type === 'PLINE') activePline = args.entity;
});
// 正常结束与 ESC 退出都只触发 CommandEnded(CommandCancelled 不派发)
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
if (args.commandName === 'PLINE' && activePline) {
console.log('最终点数:', activePline.bulgePoints.items.length);
}
activePline = null;
});
MCP 参考:vjcad/example/event/06plinepoints.js,详见 pline-timing。
六、用 CommandEnded 做"绘图后处理"
如果在 EntityAdded 里改实体属性,会被后续的命令交互再覆盖(PLINE 加点会重置某些字段)。最稳的做法是在 CommandEnded 里改:
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
if (args.commandName === 'CIRCLE') {
const last = Engine.getEntities(e => e.type === 'CIRCLE').slice(-1)[0];
if (last) {
last.color = 1;
last.layer = '装饰层';
last.setModified();
}
}
});
反例
- 在
CommandStarting里弹出 confirm():阻塞主线程,所有命令变慢。 - 不分
Started/Ended,把统计逻辑放在Started:命令还没执行就被计数。注意Ended同样无法区分"完成"和"ESC 取消",要统计完成数需自行判断(如命令前后实体数 /UndoStackChanged)。 - 订阅
CommandCancelled处理取消分支:该事件不派发,分支永远不执行。 args.commandName大小写不一致:vjcad 命令名一般是大写('PLINE'、'CIRCLE'),写'pline'比较不上。
参考(官方文档 MCP)
- 文档:
vjcad/doc/event/event-types.md、vjcad/doc/event/event-usage.md - 示例:
vjcad/example/event/04commandevents.js、06plinepoints.js