用户交互
AutoCAD 的命令行交互模型通过 Editor 类封装。本章涵盖提示输入、选择集、Jig(动态拖拽)等技术。
Editor 核心方法
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;| 方法 | 返回类型 | 用途 |
|---|---|---|
GetPoint |
PromptPointResult |
获取一个点 |
GetDistance |
PromptDistanceResult |
获取距离 |
GetAngle |
PromptAngleResult |
获取角度 |
GetString |
PromptResult |
获取字符串 |
GetInteger |
PromptIntegerResult |
获取整数 |
GetDouble |
PromptDoubleResult |
获取浮点数 |
GetKeyword |
PromptResult |
获取关键字选择 |
GetEntity |
PromptEntityResult |
选择单个实体 |
GetSelection |
PromptSelectionResult |
选择多个实体 |
SelectAll |
PromptSelectionResult |
选择全部实体 |
WriteMessage |
void |
输出消息到命令行 |
获取点
[CommandMethod("GETPOINT")]
public void GetPointExample()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
// 基本点输入
PromptPointOptions ppo = new PromptPointOptions("\n请选择一个点:");
PromptPointResult ppr = ed.GetPoint(ppo);
if (ppr.Status == PromptStatus.OK)
{
ed.WriteMessage($"\n选择点:{ppr.Value}");
}
else if (ppr.Status == PromptStatus.Cancel)
{
ed.WriteMessage("\n用户取消了操作。");
}
// 带基点的橡皮筋效果
PromptPointOptions ppo2 = new PromptPointOptions("\n请选择下一点:");
ppo2.BasePoint = previousPoint;
ppo2.UseBasePoint = true;
// 带关键字的点输入
PromptPointOptions ppo3 = new PromptPointOptions("\n选择点或 [退出(E)]:");
ppo3.Keywords.Add("Exit", "E", "退出(E)");
PromptPointResult ppr3 = ed.GetPoint(ppo3);
if (ppr3.Status == PromptStatus.Keyword)
{
if (ppr3.StringResult == "Exit")
return;
}
}PromptStatus 枚举
| 值 | 含义 |
|---|---|
OK |
用户提供了有效输入 |
Cancel |
用户按 Esc 取消 |
Error |
发生错误 |
Keyword |
用户输入了关键字 |
None |
用户直接回车(空输入) |
Other |
其他情况 |
Modeless |
非模态操作中断 |
获取字符串与数值
// 获取字符串
PromptStringOptions pso = new PromptStringOptions("\n输入名称:");
pso.AllowSpaces = true;
PromptResult pr = ed.GetString(pso);
string name = pr.StringResult;
// 获取整数
PromptIntegerOptions pio = new PromptIntegerOptions("\n输入数量:");
pio.LowerLimit = 1;
pio.UpperLimit = 100;
pio.DefaultValue = 5;
PromptIntegerResult pir = ed.GetInteger(pio);
int count = pir.Value;
// 获取浮点数
PromptDoubleOptions pdo = new PromptDoubleOptions("\n输入半径:");
pdo.AllowNegative = false;
pdo.AllowZero = false;
PromptDoubleResult pdr = ed.GetDouble(pdo);
double radius = pdr.Value;
// 获取距离(可通过两点或直接输入)
PromptDistanceOptions pdistOpts = new PromptDistanceOptions("\n输入距离:");
PromptDoubleResult pdist = ed.GetDistance(pdistOpts);
double distance = pdist.Value;
// 获取角度
PromptAngleOptions pao = new PromptAngleOptions("\n输入角度:");
PromptDoubleResult par = ed.GetAngle(pao);
double angleRad = par.Value; // 弧度关键字选择
[CommandMethod("KEYWORDDEMO")]
public void KeywordDemo()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptKeywordOptions pko = new PromptKeywordOptions("\n选择操作 [画线(L)/画圆(C)/退出(X)]:");
pko.Keywords.Add("Line", "L", "画线(L)");
pko.Keywords.Add("Circle", "C", "画圆(C)");
pko.Keywords.Add("Exit", "X", "退出(X)");
pko.AllowNone = true;
pko.Keywords.Default = "Line";
PromptResult pr = ed.GetKeywords(pko);
if (pr.Status == PromptStatus.OK || pr.Status == PromptStatus.Keyword)
{
switch (pr.StringResult)
{
case "Line":
DrawLine();
break;
case "Circle":
DrawCircle();
break;
case "Exit":
return;
}
}
}选择集
选择单个实体
PromptEntityOptions peo = new PromptEntityOptions("\n选择一条直线:");
peo.SetRejectMessage("\n必须是直线!");
peo.AddAllowedClass(typeof(Line), exactMatch: true); // 仅允许直线
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status == PromptStatus.OK)
{
ObjectId selectedId = per.ObjectId;
Point3d pickedPoint = per.PickedPoint;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Line line = tr.GetObject(selectedId, OpenMode.ForRead) as Line;
if (line != null)
{
ed.WriteMessage($"\n直线长度:{line.Length:F2}");
}
tr.Commit();
}
}多实体选择
// 手动选择过滤
PromptSelectionOptions pso = new PromptSelectionOptions();
pso.MessageForAdding = "\n选择实体(添加到选择集):";
pso.MessageForRemoval = "\n选择实体(从选择集移除):";
TypedValue[] filterList = new TypedValue[]
{
new TypedValue((int)DxfCode.Start, "LINE"), // 只选直线
// new TypedValue((int)DxfCode.LayerName, "WALL"), // 限定图层
};
SelectionFilter filter = new SelectionFilter(filterList);
PromptSelectionResult psr = ed.GetSelection(pso, filter);
if (psr.Status == PromptStatus.OK)
{
SelectionSet ss = psr.Value;
ObjectId[] ids = ss.GetObjectIds();
foreach (ObjectId id in ids)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Line line = tr.GetObject(id, OpenMode.ForRead) as Line;
if (line != null)
{
ed.WriteMessage($"\n{line.ObjectId} 长度={line.Length:F2}");
}
tr.Commit();
}
}
}
// 选择全部
PromptSelectionResult allResult = ed.SelectAll(filter);选择集过滤 DXfCode 常用值
| DxfCode | 含义 | 示例 TypedValue |
|---|---|---|
DxfCode.Start (0) |
实体类型 | (0, "LINE") |
DxfCode.LayerName (8) |
图层名 | (8, "WALL") |
DxfCode.Color (62) |
颜色 | (62, 1) |
DxfCode.LinetypeName (6) |
线型 | (6, "DASHED") |
DxfCode.BlockName (2) |
块名 | (2, "DOOR") |
DxfCode.TextString (1) |
文字内容 | (1, "*门*") |
-4 |
逻辑操作符 | (-4, "<AND") … (-4, "AND>") |
// 复杂过滤:图层 = WALL 且颜色 = 红色 的直线或圆
TypedValue[] filter = new TypedValue[]
{
new TypedValue((int)DxfCode.Operator, "<AND"),
new TypedValue((int)DxfCode.Operator, "<OR"),
new TypedValue((int)DxfCode.Start, "LINE"),
new TypedValue((int)DxfCode.Start, "CIRCLE"),
new TypedValue((int)DxfCode.Operator, "OR>"),
new TypedValue((int)DxfCode.LayerName, "WALL"),
new TypedValue((int)DxfCode.Color, 1),
new TypedValue((int)DxfCode.Operator, "AND>"),
};Jig —— 动态拖拽交互
Jig 是 AutoCAD 中实现"拖拽预览"的机制,如 LINE 命令画线时的橡皮筋效果。
// 自定义 Jig:动态拖拽一个圆
public class CircleJig : DrawJig
{
private Point3d _center;
private double _radius;
public CircleJig(Point3d initialCenter)
{
_center = initialCenter;
_radius = 1.0;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
// 获取用户输入(拖拽点或输入半径值)
JigPromptDistanceOptions jdo = new JigPromptDistanceOptions("\n输入半径:");
jdo.BasePoint = _center;
jdo.UseBasePoint = true;
jdo.Cursor = CursorType.RubberBand;
PromptDoubleResult pdr = prompts.AcquireDistance(jdo);
if (pdr.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (pdr.Value == _radius)
return SamplerStatus.NoChange;
_radius = pdr.Value;
return SamplerStatus.OK;
}
protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
{
// 绘制预览
var circle = new Circle(_center, Vector3d.ZAxis, _radius);
draw.Geometry.Draw(circle);
return true;
}
// 获取最终结果
public Circle GetCircle()
{
return new Circle(_center, Vector3d.ZAxis, _radius);
}
}
// 使用 Jig
[CommandMethod("JIGCIRCLE")]
public void JigCircleCommand()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// 获取圆心
PromptPointResult ppr = ed.GetPoint("\n指定圆心:");
if (ppr.Status != PromptStatus.OK) return;
// 启动 Jig
CircleJig jig = new CircleJig(ppr.Value);
PromptResult jigResult = ed.Drag(jig);
if (jigResult.Status == PromptStatus.OK)
{
Circle circle = jig.GetCircle();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord ms = (BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
ms.AppendEntity(circle);
tr.AddNewlyCreatedDBObject(circle, true);
tr.Commit();
}
}
}💡 Jig 有两种基类:
DrawJig(通用拖拽,需自己绘制预览)和EntityJig(围绕单个实体操作)。DrawJig更灵活,EntityJig更简单但有局限。
输出到命令行
Editor ed = doc.Editor;
// 基本输出(\n 使内容在新行开始,否则追加当前行)
ed.WriteMessage("\n处理完成。");
ed.WriteMessage("\n共处理 {0} 个实体,耗时 {1:F2} 秒。", count, elapsed);
// 控制输出目标
ed.WriteMessage("\nHello"); // 命令行
// 弹窗(调试用,避免作为常规交互方式)
System.Windows.Forms.MessageBox.Show("操作完成", "提示");🚨
WriteMessage的输出以\n开头才独占新行——AutoCAD 的命令行默认追加模式。忘了\n会导致输出粘在前面的内容上。