Skip to content
C#
用户交互

用户交互

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 会导致输出粘在前面的内容上。