简介:面向TEKLA二次开发入门者的C#源代码包,聚焦钢结构详图设计中图纸模块的自动化处理,适合具备一定.NET编程基础、希望扩展TEKLA功能的设计人员。压缩包共20个文件,以6个.cs源码文件为核心,包含实现图纸界面的Form1.cs、程序入口Program.cs,配合.csproj工程文件、.sln解决方案与.resx资源文件,可完整编译为一个WinForms示例;另有.suo、.vsidx等Visual Studio状态文件,不影响项目结构。整个压缩包仅74KB,轻量易读。示例串联载入模型图纸列表、选择模型图纸、打开模型图纸、取图纸数值四个关键流程,展示如何调用TEKLA API读取项目图纸数据、更新界面并提取几何与属性信息,为后续定制出图、批量处理图纸等实际需求提供可参考的代码骨架。已有781人学习浏览,适合作为从界面操作走向二次开发的进阶起点。 TEKLA做深化这行,凡是干过几年的,多少都会碰到被图纸逼疯的时刻:几百张构件图要改标记前缀、调尺寸样式、加文本说明,手工一张张点过去,一晚上就没了。我最早接触TEKLA二次开发,就是因为一次要改四百多张图的零件标记,人点在屏幕前差点睡着。后来花两天写了段C#脚本,十分钟跑完,从那以后就再也没离开过这玩意儿。
这篇帖子面向的是刚准备入门TEKLA二次开发的朋友,重点是"图纸"这个模块。建模阶段的API相对直接,图纸才是真正让人掉头发的地方——视图、标记、尺寸、标签、图纸对象遍历,每个环节都有自己的一套逻辑。我会把最核心的对象模型讲清楚,再给三段可以直接抄的源码,最后把我们踩过的坑挨个列出来,省得你重复走弯路。
1. 图纸二次开发的核心思路与对象模型
1.1 为什么要从图纸入手搞二次开发
直接用宏录制功能可以解燃眉之急,但录出来的代码又长又没法灵活复用。图纸二次开发的价值在于批量化和自动化:当你面对几十张、几百张图纸时,手工操作和高阶脚本的差距是数量级的。而且图纸深化恰恰是项目周期中最容易赶工期的环节,能在这里省下时间,整个项目的交付压力都会小很多。
图纸开发还有个特点:它和建模是两套独立的API体系。很多从建模开发转过来的人会一头雾水,因为图纸API的设计思路偏"文档对象模型",操作方式更接近CAD二次开发。理解这层关系,后面上手会顺很多。
1.2 必须认识的几个对象:Drawing、View、Mark、Dimension
TEKLA图纸的对象模型可以概括为四个层次:
- Drawing(图纸):最顶层对象,对应一张图纸文件。包含图纸页(Sheet)、视图(View)和所有图纸对象。通过DrawingHandler可以获取当前模型里打开或激活的图纸。
- View(视图):图纸里的一个视口,比如主视图、剖面图、详图。视图有自己的坐标系和视图属性(ViewAttributes),比如比例、视角方向。操作图纸时,先定位到具体视图,再处理视图里的内容。
- Mark(标记):零件标记、构件标记、视图标记等都继承自Mark。每个Mark都带着一串复杂的属性字符串,这个字符串控制着标记显示的内容和格式。
- Dimension(尺寸):尺寸标注对象,包括线性尺寸、径向尺寸、角度尺寸等。修改尺寸和添加尺寸是图纸自动化里非常高频的操作。
此外还有Label(标签)、Text(文本)、Symbol(符号)等对象,它们在图纸里以独立元素存在,常用在添加说明、图名标题等场景。
画个简单的对应关系你就明白了:Drawing相当于Word文档,View相当于文档里的一个章节,Mark和Dimension相当于章节里的文字和图片。要对文档做批量修改,你得分清自己操作的是哪个层级,不同层级的属性和方法完全不同。
2. 开发环境准备与项目配置
2.1 程序集引用与版本选择
TEKLA二次开发用的是.NET(C#为主),最低版本要求取决于你用的TEKLA版本。以我常用的TEKLA 21.1和2022为例,你需要引用的核心程序集是:
- Tekla.Structures.dll:基础类型,包括几何对象、模型对象选择器等。
- Tekla.Structures.Drawing.dll:图纸API,所有图纸相关操作都在这里。
- Tekla.Structures.Model.dll:建模API,虽然做图纸开发,但获取模型对象信息时经常要用。
- Tekla.Structures.Catalogs.dll:型材库、螺栓库等目录数据访问。
这些dll在TEKLA安装目录下的nt\bin文件夹里。引用的时候记得选"复制本地"为false,避免把整个TEKLA的dll拷贝到你的输出目录,否则运行时容易出现版本冲突。我个人习惯直接把输出路径设置到TEKLA的nt\bin\plugins目录,这样F5调试时可以直接以插件的形式挂载到TEKLA进程里。
2.2 最简单的工程骨架
创建一个类库项目(.NET Framework 4.7.2以上),在入口方法里写好连接判断和异常处理。一个标准的二级开发入口长这样:
using Tekla.Structures.Drawing; using Tekla.Structures.Model; public class DrawingDemo { public static void Run() { DrawingHandler drawingHandler = new DrawingHandler(); if (!drawingHandler.GetConnectionStatus()) { // 说明当前没有打开TEKLA模型 return; } Drawing drawing = drawingHandler.GetDrawing(); if (drawing == null) { // 当前没有激活的图纸,需要先在TEKLA里打开一张图纸 return; } // 在这里写你的图纸处理逻辑 } }这段代码是整个图纸二次开发的"地基"。GetConnectionStatus()这个方法是用来确认当前进程是否连接到了正在运行的TEKLA实例,没有它你后续所有API调用都会返回null或者报错。GetDrawing()则返回当前激活状态的图纸对象,这里的"激活"指的是TEKLA界面上当前打开并且处于前台的那张图纸。
提示:如果你的代码不是通过插件按钮触发,而是独立运行的exe,必须在项目设置里勾选"支持32位应用程序"(如果你的TEKLA是32位),否则连接时会直接崩。
3. 源码解析:三个必会入门操作
3.1 在代码里拿到当前图纸和视图
图纸开发的第一步永远是获取图纸对象和视图列表。这里有个小技巧:GetDrawing()只能拿到当前激活的图纸,但很多场景下你需要处理的是模型里的所有图纸。这时要用GetDrawings()方法,然后遍历返回的枚举器。
// 获取当前激活图纸 Drawing drawing = drawingHandler.GetDrawing(); // 遍历模型里所有图纸(用于批量处理) DrawingEnumerator drawingEnumerator = drawingHandler.GetDrawings(); while (drawingEnumerator.MoveNext()) { Drawing currentDrawing = drawingEnumerator.Current; // 对每张图纸执行操作 }拿到图纸后,下一步通常是遍历视图。视图对象决定了你后续操作的作用域,比如你要改视图比例、调整视图标签位置,都需要先拿到对应的View对象。
ViewEnumerator viewEnumerator = drawing.GetViews(); while (viewEnumerator.MoveNext()) { View view = viewEnumerator.Current; // 获取视图属性 ViewAttributes viewAttributes = view.GetViewAttributes(); // 注意:这里拿到的属性是引用还是副本,取决于具体方法 // 修改后用 view.Modify() 或者 view.SetViewAttributes() 回写 }有个细节容易忽略:用GetViews()拿到的只是第一层视图,如果图纸里存在剖面图、详图这类嵌套视图,它们不会被枚举出来。如果确实需要递归处理所有层级的视图,得自己写递归逻辑,遍历视图的ChildViews属性。大多数情况下第一层视图(主视图)已经够用了,但你要是处理复杂构件详图,嵌套视图这关迟早要过。
3.2 批量改零件标记属性
这是图纸自动化里最经典的需求。模型里几百个零件,改了规格后所有图纸的零件标记都要刷新,手工改得改到天亮,用脚本就是几分钟的事。
先看一个最简单的遍历标记的代码:
using System.Collections; // 遍历图纸内的所有对象,找出零件标记 DrawingObjectEnumerator drawingObjects = drawing.GetObjects(); while (drawingObjects.MoveNext()) { DrawingObject drawingObject = drawingObjects.Current; if (drawingObject is PartMark partMark) { // partMark 就是零件标记对象 // 在这里对标记做处理 } }这里有个需要特别注意的坑:GetObjects()返回的枚举器不会自动重置。也就是说,同一张图纸里,如果你先遍历了一遍找到标记,想再遍历一遍找尺寸,必须重新调用GetObjects()获取新的枚举器,否则循环直接结束。我在最早写脚本时就栽在这里,查了半天以为是图纸没对象,其实是枚举器已经走到头了。
修改标记内容的场景,通常不是改文字本身,而是改标记类型、隐藏某些属性、调整内容顺序。这些操作都建立在理解Mark属性的字符串格式之上。
if (drawingObject is PartMark partMark) { // 获取标记内容元素列表(每个标记由多个元素组成) Mark.ContentElements contentElements = partMark.GetContentElements(); // 遍历内容元素 for (int i = 0; i < contentElements.Count; i++) { MarkContentElement element = contentElements[i]; // 每个元素里的各个字段,代表不同的标记内容 // 比如零件位置、规格、材质等 } }说句实在话,标记内容的字符串格式在早期版本非常不直观,看文档不如直接上手调试。我的笨办法是在标记上右键查看属性,找到对应内容的顺序,再回到代码里定位元素下标。调试几次你就能摸清楚规律了。修改完标记属性之后,记得调用partMark.Modify()提交修改,这一步漏了,改了跟没改一样。
3.3 在图纸里加文本、挪标记位置
图纸调整里还有个高频操作:加文本说明和手动挪动标记位置。文本对象是最友好的入门对象,参数简单,不容易出错。
using Tekla.Structures.Geometry3d; // 在图纸坐标系下创建一个文本 Point insertionPoint = new Point(50, 50, 0); Text text = new Text(drawing, insertionPoint, "这是自动添加的说明文字"); text.Height = 3.5; // 文字高度 text.Font = "Arial"; text.Color = new Color(1.0, 0.0, 0.0); // 红色 text.Insert();这里要注意坐标系。图纸空间的Point是图纸坐标系,原点在图纸左下角。跟模型空间的三维坐标是两套体系,别混用。很多人第一次写,直接在模型坐标里取了个点往图纸里塞,结果文字跑到图纸外面去了。
标记位置的重新定位,用InsertionPoints来完成。每个标记有多个插入点,对应着标记的不同位置选项。你可以先获取当前插入点信息,再重新赋值并调用Modify()。
ArrayList insertionPoints = new ArrayList(); partMark.GetInsertionPoints(insertionPoints); if (insertionPoints.Count > 0 && insertionPoints[0] is InsertionPoint insertionPoint) { // 把第一个插入点挪到新的位置 insertionPoint.MovePoint(new Point(100, 200, 0)); partMark.Modify(); }这个操作的难点在于"新位置从哪来"。如果是固定偏移,直接加一个偏移量就行;如果是根据其他对象的位置来定位,就得先从那些对象身上读取坐标再计算。比如你想把构件标记统一挪到视图右上角,那要先拿到视图的范围属性,再做坐标换算。这块逻辑不复杂但很琐碎,建议分段调试。
4. 常见问题与排查技巧实录
4.1 遍历图纸对象时类型判断的坑
图纸对象类型非常多,GetObjects()返回的对象可能是Mark、Dimension、Text、Symbol、Label,还有各种辅助对象。直接用is关键字判断类型是最简单的,但要注意继承关系:PartMark继承自Mark,AssemblyMark也继承自Mark。如果你用is Mark来判断,会把所有标记类型一网打尽;如果你只想处理零件标记,就必须用is PartMark或is AssemblyMark来区分。
我自己实际写代码时,习惯先判断Mark再通过Mark.MarkType枚举来区分具体类型,这样代码结构更清晰,后续加逻辑也好维护。
if (drawingObject is Mark mark) { switch (mark.MarkType) { case MarkType.PART_MARK: // 零件标记处理 break; case MarkType.ASSEMBLY_MARK: // 构件标记处理 break; case MarkType.VIEW_MARK: // 视图标记处理 break; } }4.2 修改不生效:Modify和CommitChanges别漏
新手最容易遇到的情况是:代码跑完没报错,但图纸上啥变化也没有。一大半原因是没有调用Modify()方法。TEKLA的对象模型里,大部分修改操作都是"先改属性,再提交",Modify()就是提交动作。漏掉这一步,你前面做的一切都是白费。
但也有例外。比如你改了ViewAttributes里的比例,这时候除了View.Modify(),可能还需要调用drawing.CommitChanges()才会真正刷新视图。我的经验是:改完任何对象,先调该对象的Modify(),如果还是没变化,再调图纸级别的CommitChanges(),基本能解决90%的问题。
提示:批量处理大量对象时,避免每个对象都调一次
CommitChanges(),性能损耗很大。建议全部改完、最后统一提交一次。
4.3 版本兼容性:17.0到2024的API差异
标题里的热搜词有"TEKLA版本转换工具17.0-2024",这侧面说明了一个现实问题:TEKLA跨版本的项目文件转换本身就麻烦,二次开发API更是有版本差异。我接触过的策略有两条路:一是针对特定TEKLA版本开发,输出dll只在该版本下运行;二是用宏录制功能生成代码,再改造成通用逻辑。
需要注意的风险点是:不同版本的API可能存在方法名称变化或者行为差异。比如早期版本里GetObjects()需要传入参数,后期版本改成了无参版本。还有InsertionPoint.MovePoint()在某个版本后行为有过变化。规避这些问题的最稳妥办法:开发时直接引用目标版本的dll,并在代码注释里标明对应的TEKLA版本号,方便后期排查。
4.4 大批量处理的性能优化
处理几百张图纸时,性能问题会被无限放大。我踩过的坑有三个,对应三个优化策略。
策略一:减少对象遍历次数。一次GetObjects()能拿到图纸里所有对象,但如果你只处理标记,可以先用过滤条件缩小范围。避免对每个对象做耗时的属性读取操作,有些属性读取会触发TEKLA内部的数据库查询。
策略二:批处理时关闭界面刷新。TEKLA提供了一个刷新控制的开关,批量改属性时临时关闭界面刷新,所有操作完成后再统一刷新。视觉上会变卡顿,但处理时间能缩短一半以上。
策略三:分批提交和保存。每处理完一批图纸(比如50张),调用一次保存和清理操作,避免内存占用过高导致程序崩溃。尤其是处理大型模型时,图纸对象占用的内存不可小觑。
4.5 调试阶段必用的断点技巧
图纸二次开发的调试要比普通程序麻烦一些,因为代码跑在TEKLA进程里。我的调试习惯是:专门写一个Debug函数,在函数开头读取当前图纸ID和视图数量,打印到VS的输出窗口。这一步能帮你快速确认当前操作是否正确连接到了图纸对象,省得程序跑完了才发现处理的是错误图纸。
另外建议在开发的机器上保留一个只有一两张图纸的小测试模型,专门用来验证代码逻辑。直接拿实际项目的大模型来调,一次遍历就要等好几秒,效率太低了。
写在最后
图纸二次开发这块内容,说难不难,说简单也真不简单。我见过一上来就想做复杂自动化工具的,结果卡在对象模型理解上,写了几天跑不通就放弃了。我的建议是:从最具体的痛点入手,比如批量改标记、批量加文本,一个功能一个功能地写,跑通一个算一个,等这些基础操作积累够了,你自然会对整个对象模型有通盘的理解,到那时候再做复杂的自动化工具就是水到渠成的事了。
做完上面几个例程,你就可以尝试去给图纸自动添加页码、按照规则批量重命名图纸、把图纸信息导出到Excel表格,这些都是在刚才这几个基础操作上扩展出来的应用。先把地基打牢,后面想盖几层楼都是你自己说了算。
本文还有配套的精品资源,点击获取