惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
博客园 - Franky
MyScale Blog
MyScale Blog
Jina AI
Jina AI
B
Blog
Microsoft Security Blog
Microsoft Security Blog
T
Troy Hunt's Blog
博客园_首页
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
Lohrmann on Cybersecurity
GbyAI
GbyAI
T
Tenable Blog
B
Blog RSS Feed
S
Securelist
T
Threat Research - Cisco Blogs
P
Privacy International News Feed
P
Proofpoint News Feed
T
The Exploit Database - CXSecurity.com
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
博客园 - 三生石上(FineUI控件)
大猫的无限游戏
大猫的无限游戏
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
罗磊的独立博客
AWS News Blog
AWS News Blog
V
V2EX
宝玉的分享
宝玉的分享
J
Java Code Geeks
小众软件
小众软件
Spread Privacy
Spread Privacy
腾讯CDC
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
V
Visual Studio Blog
The Hacker News
The Hacker News
C
CERT Recently Published Vulnerability Notes
Project Zero
Project Zero
Know Your Adversary
Know Your Adversary
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
Apple Machine Learning Research
Apple Machine Learning Research
NISL@THU
NISL@THU
C
Check Point Blog
Webroot Blog
Webroot Blog
D
DataBreaches.Net
Cloudbric
Cloudbric
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家

博客园 - 梦想CAD控件

网页CAD图纸保存与数据持久化(BS架构CAD插件) 在线CAD视图控制与图层管理二开实战 Web CAD图形引擎实现DWG图纸网页批注和查看 开源网页实时协同设计平台-在线编辑CAD图纸 在线CAD SDK开发包图纸转换功能使用教程(在线CAD API) 统信麒麟鸿蒙系统软件集成CAD功能(国产系统CAD控件) 网页CAD开发包结构与功能说明(网页CAD实时协同编辑) 网页CAD结合AI实现自然语言设计CAD图纸 (JS实现预览)在线CAD中的“组”功能开发 (在线CAD)html在线预览cad图纸SDK集成方法 (JS编辑DWG文件)在线CAD二开实现图纸表格提取到excel 网页版CAD与gis结合实现在线地图和CAD编辑 (html在线预览cad图纸插件)在线CAD实现形位公差标注 (WEB CAD API )网页CAD插件如何开发焊接符号 (HTML VUE在线编辑DWG)网页CAD利用AI实现多行文本功能的开发 (web cad sdk)在线CAD中配置属性的使用教程 (WEB CAD二次开发)在线CAD SDK调用内部弹框的方法 在线CAD插件通过上下文对象MxPluginContext修改UI界面的方法 国产操作系统中好用的CAD软件(统信,麒麟,信创环境安装CAD) (pdm集成CAD SDK)在线CAD绘制条形码、二维码的教程 在线CAD绘制门和窗(WEB CAD二次开发家装设计软件) 在线CAD绘制墙体(WEB端开发室内设计软件) (在线三维参数化建模)网页三维CAD中加载和保存STEP模型 (H5在线CAD SDK)在线CAD中线型表的使用方法 (web查看三维CAD图纸)在三维网页CAD中绘制一个窗户模型
网页CAD中命令行驱动与参数化绘图的使用教程
梦想CAD控件 · 2026-06-24 · via 博客园 - 梦想CAD控件

前言

在前几篇文章中,我们已经完成了MxCAD Web端开发的“筑基”阶段。通过《MxCAD产品介绍》与《云开发包使用说明》,我们了解了MxCAD的核心能力并配置好了开发环境;借助《图纸转换详细说明》与《MxCAD/MxDraw Web预览批注实战》,我们实现了DWG图纸的云端转换与基础浏览批注功能;最后,通过《视图控制与图层管理系统实现》,我们学会了如何像专业CAD软件一样管理图纸的显示与结构。
至此,我们的Web CAD项目已经能够“看”图纸了。但目前的程序还停留在“静态浏览”的层面,缺乏主动“画”图的能力。用户无法通过指令来创建图形,也无法精确控制绘图的参数。
本文将带领大家进入“进阶”阶段,重点攻克CAD软件最核心的交互逻辑:命令行系统参数化绘图。我们将不再依赖鼠标凭感觉绘图,而是通过构建命令行驱动机制,让用户能够输入指令、输入数值,实现精确、动态的图形绘制。

一、为什么要引入命令行机制?

1.1 传统开发的痛点:混乱与低效

在早前的MxCAD开发实践中,我们往往采用如下模式:

  1. 代码分散:画圆的逻辑写在Circle.js,画线的逻辑写在Line.js,调用时通过UI按钮直接绑定函数。
  2. 难以管理:当项目拥有数百个绘图命令时,成百上千个函数散布在各个文件中,缺乏统一的管理入口。
  3. 交互受限:用户只能通过点击UI按钮触发功能,无法像使用AutoCAD那样通过键盘输入指令,也无法在绘图过程中通过键盘输入参数(如长度、半径)。
    这种“面条式”的代码结构在小型Demo中尚可,但在企业级CAD项目中是致命的。我们需要一种机制,将所有功能像“插件”一样注册到系统中,统一管理,统一调用。

1.2 命令行的核心价值

MxCAD提供的命令行机制,正是为了解决上述问题而生。

  • 集中管理:所有功能通过唯一的名称(Name)进行注册和索引。
  • 多入口调用:注册后的命令,既可以通过代码调用,也可以通过UI菜单、快捷键,甚至是底部的命令行输入框直接触发。
  • 解耦:UI层与业务逻辑层解耦,UI只负责发送“指令名”,具体的绘图逻辑由命令系统分发。

二、命令行的构建与注册

在MxCAD中,实现一套完整的命令行系统并非一蹴而就,它需要经历UI搭建、事件监听、命令注册、指令执行四个核心步骤。这就好比我们要造一辆车,先要有方向盘(UI),再连接转向柱(监听),然后安装发动机(注册),最后才能点火起步(执行)。

2.1 步骤一:搭建命令行UI界面

我们在UI界面中创建黑色的消息显示区和底部的输入框。这是用户与我们程序交互的“窗口”。

<!-- 绘图容器,占据大部分高度 -->
<div style="height: 80vh; overflow: hidden;">
  <canvas id="myCanvas"></canvas>
</div>

<!-- 命令行容器,底部固定区域 -->
<div style="width: 100%; height: 12vh;">
  <!-- 只读文本域,用于显示历史消息和提示(黑色背景,绿色文字风格) -->
  <textarea 
    id="myArea" 
    style="width: 100%; height: 8vh; background-color: #000; color: #fff; border-radius: 5px" 
    readonly="true">
  </textarea>
  
  <!-- 输入框,用户在此输入命令 -->
  <input 
    id="myInput" 
    style="width:100%; height: 2vh; background-color: #000; color: #fff;" 
  />
</div>

image-20260413170604751

2.2 步骤二:监听命令(连接输入与输出)

有了界面,我们需要让程序“听懂”用户在输入框里敲了什么,并且把程序的反馈显示在消息区。
根据图一的代码逻辑,我们需要做两件事:

  1. 监听用户输入:当用户在输入框按键时,通过 MxFun.setCommandLineInputData() 告诉MxCAD内核。
  2. 监听消息变化:当MxCAD内核有提示(比如“请点击起点”)时,通过 MxFun.listenForCommandLineInput() 把这些话显示在我们的消息区里。
import { MxFun } from "mxdraw"
// 1. 获取DOM元素:获取我们在HTML中定义的输入框和消息显示区
const inputBox = document.getElementById("myInput")
const cmdWindow = document.getElementById("myArea")

// 2. 监听用户输入:准备一个变量存储当前输入的内容
let inputText = ""
inputBox.oninput = () => {
  inputText = inputBox.value
}

// 3. 监听键盘事件:当用户按下键盘(回车或普通按键)时
inputBox.onkeydown = (e) => {
  // 将用户的输入内容和按键码传给MxCAD内核进行处理
  MxFun.setCommandLineInputData(inputText, e.keyCode)

  // 如果按下的是回车键 (keyCode 13),代表命令发送
  if (e.keyCode === 13) {
    // 清空输入框,准备下一次输入
    inputText = inputBox.value = ""
  }
}

// 4. 监听内核消息:监听MxCAD内核返回的消息变化
MxFun.listenForCommandLineInput(({
  msCmdTip,      // 提示信息(如:指定下一点)
  msCmdDisplay,  // 历史消息显示(之前的所有对话)
  msCmdText      // 当前命令文本
}) => {
  // 将内核返回的消息拼接并显示在我们的HTML元素中
  cmdWindow.value = msCmdDisplay + "\n" + msCmdTip
  // 自动滚动到底部,确保用户看到最新消息
  cmdWindow.scrollTop = cmdWindow.scrollHeight
})

2.3 步骤三:注册命令(安装发动机)

监听做好了,现在我们需要告诉MxCAD:“如果用户输入了某个特定的词(比如 Mx_test),你应该去执行哪段代码”。这就是命令注册

我们需要使用 MxFun.addCommand() 方法。这就像是在前台注册一个服务,告诉系统:“当听到‘画线’指令时,请调用‘画线功能’”。

import { MxFun } from "mxdraw"
// 注册命令:名称为 "Mx_test"
// 以后用户在底部输入框输入 Mx_test,就会执行后面的箭头函数
MxFun.addCommand("Mx_test", async () => {
  // 这里暂时留空,具体的绘图逻辑写在下一节
  alert("命令已触发!");
});

2.4 步骤四:执行命令(点火启动)

完成上一步操作后,mxcad对象中就已经写入了CAD命令Mx_test,接下来用户只需要调用MxFun.sendStringToExecute()函数就能在CAD项目中的任意时机或位置执行绘制方法了。

import { MxFun } from "mxdraw"
// 模拟用户输入执行:这行代码会触发上面注册的命令
// 相当于用户在命令行输入了 "Mx_test" 并按下了回车
MxFun.sendStringToExecute("Mx_test");

通过以上四个步骤,我们就成功打通了从“用户输入指令”到“程序响应绘图”的完整链路。
image-20260413170842499


三、参数化绘制功能介绍

通过上文的操作步骤,我们学会了如何通过命令行与用户进行“对话”。但现在的程序还有一个问题:它虽然听懂了指令,但画图时还是太“死板”。
所谓的参数化绘制,简单来说,就是让绘图过程变得“可控”和“精确”。我们将这部分内容分为两个阶段来讲解:

  1. 静态参数化绘制:直接在代码里写死参数(适合简单场景,但不够灵活)。
  2. 动态UI交互绘制:用户鼠标拖动时,图形实时变化,且能输入具体数值(专业CAD的标准)。

3.1 静态参数化绘制:代码写死的局限

所谓“静态”,就是我们在代码里直接规定好图形的所有属性。

场景模拟
我们要画一条线。在代码里直接写 :

import { MxCpp } from "mxcad";
const mxcad = MxCpp.getCurrentMxCAD(); // 获取当前CAD编辑器实例
mxcad.newFile(); // 创建新画布
// 绘制直线:坐标和长度完全写死
// 这条线永远是从 (1000, 800) 画到 (-1000, -800)
mxcad.drawLine(1000, 800, -1000, -800) 

缺点

  • 位置固定:直线坐标固定,无法根据用户鼠标点击的位置变化。
  • 长度固定:直线长度固定,用户无法根据需求自助修改。
  • 体验极差:这就像是给用户一张打印好的图纸,而不是一个绘图工具。

为了解决这个问题,我们需要引入动态UI交互绘制

3.2 动态UI交互绘制:让图形“活”起来

在CAD中,当你点击“画圆”命令后,移动鼠标,圆的大小会跟随鼠标实时变化,直到你点击确认。这种“所见即所得”的过程,就是动态交互。
要实现这个过程,我们需要用到MxCAD提供的核心武器——UI交互API

3.3 核心UI交互API介绍

在MxCAD中,所有的交互(画线、画圆、选点)都依赖于MxCADUiPrBase及其子类(如MxCADUiPrPointMxCADUiPrDist)。

核心工作流

  1. 实例化:创建一个交互对象(比如“获取点”对象)。
  2. 设置提示:告诉用户该做什么(如“请指定圆心”)。
  3. 执行(go):启动交互,程序暂停等待用户操作。
  4. 获取结果:用户操作完成后,获取坐标或数值。

常用API一览

类名 (Class Name) 功能描述 (Description) 典型应用场景 (Use Case)
MxCADUiPrPoint 点输入。请求用户在屏幕上点击一个点,或输入坐标。 确定直线的起点、圆心位置、文字插入点。
MxCADUiPrDist 距离输入。请求用户输入一个数值距离,通常配合两点测量或直接键盘输入。 设置圆的半径、矩形的宽度、阵列的间距。
MxCADUiPrAngl 角度输入。请求用户输入一个角度值,或通过两点确定角度。 绘制斜线、旋转对象、扇形的起始角。
MxCADUiPrInt 整数输入。仅接受整数值输入。 设置阵列的行数/列数、线的数量、多边形的边数。
MxCADUiPrKeyWord 关键字输入。提供一组预定义的选项供用户选择(如 "Yes/No", "Circle/Arc")。 命令中的子选项切换(例如画圆时的“三点(3P)/两点(2P)/相切(T)”)。
MxCADUiPrString 字符串输入。请求用户输入文本字符串。 输入文字内容、块名称、图层名称、文件名。
MxCADUiPrEntity 实体选择。请求用户在图中选择一个现有的图形对象。 修改对象属性、延伸/修剪命令的目标选择、复制/移动命令的源对象。

3.4 动态绘制核心:setUserDraw 函数详解

image-20260413172246241

动态绘制是实现用户交互绘制的重中之重

很多新手会问:“我如何在用户移动鼠标时,画布中显示当下图形的实时状态?”

答案就是 setUserDraw 函数。

  • 原理:在用户确定最终点之前(比如鼠标移动过程中),MxCAD会不断调用这个函数。
  • 作用:我们在这个函数里编写“临时绘图”的逻辑。因为是在交互过程中绘制的,所以这些图形通常被称为“橡皮筋图形”或“预览图形”。
  • 参数解析
    • currentPoint:当前鼠标光标所在的坐标点。
    • pWorldDraw:绘图上下文对象。我们需要调用它的 drawMcDbEntity 方法把图形画出来。

注意:在 setUserDraw 中绘制的图形是临时的,一旦交互结束(用户点击确认或取消),这些临时图形会自动清除,不会污染数据库。

import { MxCADUiPrPoint, McDbLine } from "mxcad"
const getPoint = new MxCADUiPrPoint() // 创建获取点对象
getPoint.go().then((point)=> { // 第一次获取点(起点)
  // 设置动态绘制回调函数
  getPoint.setUserDraw((currentPoint, pWorldDraw)=> {
    // currentPoint: 实时变化的鼠标坐标
    // pWorldDraw: 绘图工具
    if(!point) return // 防止起点为空
    // 1. 创建图形:创建一条从起点到当前鼠标点的线
    const line = new McDbLine(point, currentPoint)
    // 2. 绘制图形:将这条线画在屏幕上(临时)
    pWorldDraw.drawMcDbEntity(line)
  }) 
  // 等待第二次点击(终点)
  // 在等待期间,上面的 setUserDraw 会高频触发,实现“拖拽预览”效果
  getPoint.go()
})

3.5 完整动态绘制实例详解:绘制可交互文字

在前面的介绍中,我们了解了动态绘制的原理。现在,让我们通过一个具体的例子——“绘制文字”,将所有知识点串联起来。
在这个案例中,我们将实现一个完整的交互流程:

  1. 输入内容:用户通过键盘输入文字内容。
  2. 输入高度:用户通过鼠标拖拽或键盘输入来确定文字高度。
  3. 动态预览:用户移动鼠标时,文字跟随光标实时预览。
  4. 定点生成:用户点击鼠标,将文字永久绘制在图纸上。

image-20260413165904975

代码实现

import { McDbText, MxCADUiPrDist, MxCADUiPrPoint, MxCADUiPrString, MxCADUiPrBase, MxCpp } from "mxcad";
async function Mx_drawText() {
    // 1. 初始化:创建一个空的文字对象,稍后我们将填充它的数据
    const text = new McDbText();
    // --- 第一步:获取文字内容 ---
    // 创建“获取字符串”的交互对象
    const getStr = new MxCADUiPrString();
    // 设置命令行提示语
    getStr.setMessage("请输入文字内容:");
    // 等待用户输入(await会暂停函数,直到用户按下回车或取消)
    const str = await getStr.go();
    // 如果用户按了Esc取消,则直接退出函数
    if (!str) return;
    // 将用户输入的内容赋值给文字对象
    text.textString = str;
    // --- 第二步:获取文字高度 ---
    // 创建“获取距离”的交互对象
    const getDist = new MxCADUiPrDist();
    getDist.setMessage("请输入文字高度:");
    // 等待用户输入距离(可以通过鼠标拉距或键盘输入数值)
    const height = await getDist.go();
    if (!height) return;
    // 将获取到的数值赋值给文字高度
    text.height = getDist.value();
    // --- 第三步:动态预览与定点 ---
    // 创建“获取点”的交互对象
    const getPoint = new MxCADUiPrPoint();
    getPoint.setMessage("请点击确定文字位置:");
    // 【核心】设置动态绘制回调
    // 当用户移动鼠标时,这个函数会被反复调用
    getPoint.setUserDraw((pt, pw) => {
        // 1. 实时更新文字的位置为当前鼠标坐标(pt)
        text.position = pt;
        text.alignmentPoint = pt;
        // 2. 在预览窗口(pw)中绘制这个临时的文字
        // 用户看到的“橡皮筋”效果就是在这里产生的
        pw.drawMcDbEntity(text);
    });

    // 等待用户点击鼠标确定最终位置
    const position = await getPoint.go();
    if (!position) return;

    // --- 第四步:正式绘制 ---
    // 获取当前的CAD编辑器实例
    const mxcad = MxCpp.getCurrentMxCAD();
    // 将最终确定的文字对象添加到图纸数据库中(这一步才是永久保存)
    mxcad.drawEntity(text);
}
// --- 注册命令 ---
// 将上面写好的函数注册为一个命令
// 用户在命令行输入 "Mx_drawText" 即可触发
MxFun.addCommand("Mx_drawText", Mx_drawText);

代码逻辑解析

image-20260414135500785

这段代码完美展示了参数化绘制的“三部曲”:

  1. 参数收集(静态阶段)
    我们使用了 MxCADUiPrStringMxCADUiPrDist。这两个API专门用于在绘图前收集必要的参数。注意这里使用了 await,这意味着程序会“暂停”在这里等待用户输入,而不是直接跑完,这保证了绘图的逻辑顺序。

  2. 动态预览(交互阶段)
    这是最精彩的部分。在 getPoint.setUserDraw 中,我们并没有创建新的图形,而是不断修改同一个 text 对象的坐标,并让它画在 pWorldDraw(预览层)上。这就像是拿着一张写有字的透明胶片,在屏幕上跟着鼠标移动。

  3. 实体入库(完成阶段)
    getPoint.go() 返回最终坐标后,我们最后一次更新位置,并调用 mxcad.drawEntity(text)。这一步相当于把透明胶片上的字,真正“印”在了图纸上。

通过这种方式,我们不仅实现了绘图,还赋予了绘图过程极强的灵活性和专业感。


四、总结

通过本文的学习,我们完成了从“静态展示”到“动态交互”的跨越:

  • 命令行搭建:我们学会了如何通过HTML布局配合JS注册,构建一个标准的CAD命令行输入环境。
  • 静态参数化:理解了通过代码计算坐标进行精确绘图的基础。
  • 动态UI交互:掌握了MxCADUiPrPointMxCADUiPrInt等核心API,实现了“程序提问、用户回答、程序绘图”的完整闭环。

现在,你的CAD项目已经具备了基本的专业骨架,用户可以像操作AutoCAD一样,在底部输入指令,并通过键盘和鼠标配合来精确绘图了。