创建命令
大约 3 分钟
创建命令
本章通过完整示例展示如何创建自定义命令。
完整命令示例:绘制矩形
import {
Engine,
Point2D,
PolylineEnt,
PointInputOptions,
RealInputOptions,
InputStatusEnum,
ssSetFirst,
writeMessage
} from 'vjcad';
export class RectangleCommand {
private cornerPoint1: Point2D | null = null;
private width: number = 0;
private height: number = 0;
async main(): Promise<void> {
ssSetFirst([]); // 清空选择集
// 开始撤销标记组
Engine.undoManager.start_undoMark();
try {
// 步骤1: 获取第一个角点
const p1Result = await this.getFirstCorner();
if (!p1Result) return;
// 步骤2: 获取第二个角点或尺寸
const p2Result = await this.getSecondCorner();
if (!p2Result) return;
// 步骤3: 创建矩形
this.createRectangle();
} finally {
// 结束撤销标记组
Engine.undoManager.end_undoMark();
Engine.clearPreview();
}
}
private async getFirstCorner(): Promise<boolean> {
const options = new PointInputOptions("指定第一个角点:");
const result = await Engine.getPoint(options);
if (result.status === InputStatusEnum.OK) {
this.cornerPoint1 = result.value;
return true;
}
return false;
}
private async getSecondCorner(): Promise<boolean> {
const options = new PointInputOptions("指定另一个角点 [尺寸(D)]:");
options.keywords = ["D"];
options.useBasePoint = true;
options.basePoint = this.cornerPoint1!;
// 设置预览回调
options.onMouseMove = (currentPoint: Point2D) => {
this.drawPreview(currentPoint);
};
const result = await Engine.getPoint(options);
if (result.status === InputStatusEnum.OK) {
const p2 = result.value;
this.width = Math.abs(p2.x - this.cornerPoint1!.x);
this.height = Math.abs(p2.y - this.cornerPoint1!.y);
return true;
} else if (result.stringResult === "D") {
// 用户选择输入尺寸
return await this.getDimensions();
}
return false;
}
private async getDimensions(): Promise<boolean> {
// 获取宽度
const widthOpt = new RealInputOptions("指定矩形宽度:");
const widthResult = await Engine.getReal(widthOpt);
if (widthResult.status !== InputStatusEnum.OK) return false;
this.width = widthResult.value;
// 获取高度
const heightOpt = new RealInputOptions("指定矩形高度:");
const heightResult = await Engine.getReal(heightOpt);
if (heightResult.status !== InputStatusEnum.OK) return false;
this.height = heightResult.value;
return true;
}
private drawPreview(currentPoint: Point2D): void {
if (!this.cornerPoint1) return;
const rect = this.buildRectangle(this.cornerPoint1, currentPoint);
Engine.drawPreviewEntity(rect);
}
private buildRectangle(p1: Point2D, p2: Point2D): PolylineEnt {
const pline = new PolylineEnt();
// 使用简化接口设置顶点
pline.setPoints([
[p1.x, p1.y],
[p2.x, p1.y],
[p2.x, p2.y],
[p1.x, p2.y]
]);
pline.isClosed = true;
pline.setDefaults();
return pline;
}
private createRectangle(): void {
const p2 = new Point2D(
this.cornerPoint1!.x + this.width,
this.cornerPoint1!.y + this.height
);
const rect = this.buildRectangle(this.cornerPoint1!, p2);
// 添加到画布
Engine.pcanvas.addEntity(rect);
Engine.undoManager.added_undoMark([rect]);
// 刷新显示
Engine.pcanvas.regen();
writeMessage(`<br/>已创建矩形,宽: ${this.width}, 高: ${this.height}`);
}
}带状态机的复杂命令
对于更复杂的命令,可以使用状态机模式:
export class MultiStepCommand {
private step: number = 1;
private points: Point2D[] = [];
async main(): Promise<void> {
Engine.undoManager.start_undoMark();
while (this.step > 0) {
switch (this.step) {
case 1:
await this.step1_getFirstPoint();
break;
case 2:
await this.step2_getNextPoint();
break;
case 3:
await this.step3_finish();
break;
}
}
Engine.undoManager.end_undoMark();
}
private async step1_getFirstPoint(): Promise<void> {
const result = await Engine.getPoint(new PointInputOptions("第一点:"));
if (result.status === InputStatusEnum.OK) {
this.points.push(result.value);
this.step = 2;
} else {
this.step = 0; // 退出
}
}
private async step2_getNextPoint(): Promise<void> {
const options = new PointInputOptions("下一点 [撤销(U)/完成(F)]:");
options.keywords = ["U", "F"];
options.useBasePoint = true;
options.basePoint = this.points[this.points.length - 1];
const result = await Engine.getPoint(options);
if (result.status === InputStatusEnum.OK) {
this.points.push(result.value);
} else if (result.stringResult === "U") {
if (this.points.length > 1) {
this.points.pop();
} else {
this.step = 1;
}
} else if (result.stringResult === "F" || result.status === InputStatusEnum.EnterOrSpace) {
this.step = 3;
} else {
this.step = 0;
}
}
private async step3_finish(): Promise<void> {
if (this.points.length >= 2) {
// 创建实体...
const pline = new PolylineEnt();
// 使用 bulgePoints.add() 添加顶点
for (const p of this.points) {
pline.bulgePoints.add(new BulgePoint(new Point2D(p.x, p.y), 0));
}
pline.setDefaults();
Engine.pcanvas.addEntity(pline);
Engine.undoManager.added_undoMark([pline]);
}
this.step = 0;
}
}注册命令
import { CommandRegistry, CommandDefinition, CommandOptions } from 'vjcad';
// 注册矩形命令
CommandRegistry.regist(new CommandDefinition(
'RECTANGLE',
'绘制矩形',
RectangleCommand,
new CommandOptions()
));
// 注册多步骤命令
CommandRegistry.regist(new CommandDefinition(
'MULTISTEP',
'多步骤命令',
MultiStepCommand,
new CommandOptions()
));命令开发要点
撤销支持
// 始终使用撤销标记组
Engine.undoManager.start_undoMark();
try {
// 执行操作
} finally {
Engine.undoManager.end_undoMark();
}预览绘制
// 在鼠标移动时绘制预览
options.onMouseMove = (point: Point2D) => {
Engine.clearPreview();
const previewEntity = buildEntity(point);
Engine.drawPreviewEntity(previewEntity);
};清理工作
// 命令结束时清理
finally {
Engine.clearPreview();
Engine.undoManager.end_undoMark();
}关键字处理
if (result.stringResult === "U") {
// 撤销上一步
undoLastStep();
} else if (result.stringResult === "C") {
// 闭合
closeShape();
}