简介:这是一份面向钢结构详图设计人员与.NET开发者的TEKLA二次开发入门资料,聚焦图纸管理与数据提取方向,帮助读者理解如何借助API扩展TEKLA功能、实现图纸自动化处理。资源包共20个文件,约74KB,以C#源码文件为主,配合项目文件、解决方案文件、资源与配置文件等,构成一个可直接参考的WinForm工程结构,涵盖图纸列表载入、图纸选择、图纸打开及数值提取等典型环节的实现思路。内容围绕TEKLA数据库查询、UI交互绑定与几何属性读取展开,适合具备一定C#或VB.NET基础、希望切入TEKLA定制开发的读者对照学习。目前已有785人学习下载,可作为二次开发练手与工作流优化的起步参考。
1. TEKLA二次开发图纸入门:从看懂API到跑通第一段源代码
很多做钢结构详设的人第一次打开 TEKLA 的二次开发文档,都会卡在同一个地方:软件里明明能点出来的图纸,代码里却找不到对应对象。这不是你笨,而是 TEKLA 的图纸模型和模型空间是两套体系,图纸(Drawing)挂在模型对象下面,而不是独立存在。这篇笔记要解决的就是这件事——用源代码把「模型 → 图纸 → 视图 → 对象」这条链路打通,让你能自动批量出图、改图框、写标题栏,而不是每次手动点几十遍。适合已经会画 TEKLA 模型、想用 C# 或 Python 接管重复出图工作的结构工程师,也适合刚接触 Open API 的二次开发新手。下面所有代码都基于 TEKLA Structures 的 Open API,思路同样适用于其他版本,参数以你本机实际枚举为准。
2. 图纸对象模型:为什么你 new 不出一个 Drawing
2.1 模型空间和图纸空间是两棵树
TEKLA 的数据结构里,Model是根,ModelObject是模型里的梁、柱、板,而Drawing并不继承自ModelObject。图纸是通过DrawingHandler从模型对象上「取」出来的,不是凭空创建的。很多人翻车就翻在这里:写了一句new Drawing(),编译都过不去,因为构造函数根本不公开。
正确的取图路径是:先拿到Model,再通过DrawingHandler.GetDrawings()拿到当前模型下所有图纸,或者用GetDrawingByMark()按图号精确取。图纸下面再挂DrawingSheet,Sheet 里才是View,View 里才是DrawingObject。这条链路每一层都要用对应的 Handler 去查,不能跳级。
// 获取当前打开的模型 Model model = new Model(); // 拿到图纸处理器 DrawingHandler dh = new DrawingHandler(); // 取当前模型下所有图纸 Drawing[] drawings = dh.GetDrawings(); foreach (Drawing dwg in drawings) { // 图纸名和图号在这里 string mark = dwg.Mark; string name = dwg.Name; // 继续往下拿图纸下的视图 DrawingSheet sheet = dwg.GetSheet(); View[] views = sheet.GetViews(); }逻辑说明:new Model()拿到的是当前已打开模型的引用,不是新建模型。GetDrawings()返回的是当前模型下所有图纸的数组,如果模型里没图纸,返回空数组而不是 null,所以不用先判 null 再遍历。参数方面,dwg.Mark是图号,dwg.Name是图纸名称,这两个在出图时最常用。注意GetSheet()对某些图纸类型可能返回 null,比如多件图,所以实际项目里要加一层判断。
2.2 图纸类型决定你能改什么
TEKLA 的图纸分好几种:单件图、构件图、组装图、多件图、浇筑体图。不同类型能拿到的视图和对象不一样。单件图通常只有一个视图,构件图可能有多个视图加一个材料表。如果你写了一段代码在单件图上跑得好好的,换到构件图上就报空引用,大概率是视图数量对不上。
我一般会先判断图纸类型再决定后续操作:
if (dwg is SinglePartDrawing) { // 单件图逻辑 } else if (dwg is AssemblyDrawing) { // 构件图逻辑,视图可能不止一个 View[] views = dwg.GetSheet().GetViews(); foreach (View v in views) { // 每个视图单独处理 } }这里用is做类型判断比看字符串靠谱,因为图纸类型是强类型枚举出来的。参数上,SinglePartDrawing和AssemblyDrawing都是Drawing的子类,可以直接用父类引用接住再判断。实际项目里我习惯先写一个GetDrawingType()辅助方法,把类型转成可读字符串,方便日志排查。
2.3 视图坐标系和模型坐标系不是一回事
图纸视图里的对象坐标是图纸坐标,不是模型坐标。你在模型里量出来梁长 6000,在图纸视图里拿到的可能是缩放后的值。这个坑我在第一次做自动标注时踩得很深:按模型坐标算的标注位置,画到图纸上全偏了。
解决办法是拿视图的ViewCoordinateSystem,把模型坐标转成视图坐标:
View view = sheet.GetViews()[0]; TransformationPlane plane = view.ViewCoordinateSystem; // 把模型点转到视图坐标 Point modelPoint = new Point(1000, 2000, 0); Point viewPoint = plane.TransformationToLocal(modelPoint);TransformationToLocal把全局坐标转到视图局部坐标,反过来用TransformationToGlobal。参数上,ViewCoordinateSystem返回的是一个TransformationPlane,包含原点和三个轴方向。实际用的时候要注意视图可能被旋转过,所以不能简单加减偏移量,必须走这个转换。
3. 用源代码跑通第一张自动出图
3.1 环境准备和最小可运行工程
TEKLA Open API 分两种:一种是 .NET API,用 C# 写,功能最全;另一种是 Python 通过tekla-python包调用,适合快速脚本。我建议新手先从 C# 入手,因为官方示例和社区代码基本都是 C#,遇到问题好搜。
最小工程需要引用两个 DLL:Tekla.Structures.Model.dll和Tekla.Structures.Drawing.dll。这两个文件在 TEKLA 安装目录下的nt\bin\plugins里。新建一个 C# 控制台项目,把这两个引用加进去,目标框架选 .NET Framework 4.8,因为 TEKLA 目前对 .NET Core 支持还不完整。
using Tekla.Structures.Model; using Tekla.Structures.Drawing; class Program { static void Main(string[] args) { // 连接当前打开的 TEKLA 模型 Model model = new Model(); if (!model.GetConnectionStatus()) { Console.WriteLine("没连上 TEKLA,检查软件是否打开"); return; } DrawingHandler dh = new DrawingHandler(); Drawing[] drawings = dh.GetDrawings(); Console.WriteLine($"当前模型共有 {drawings.Length} 张图纸"); } }逻辑说明:GetConnectionStatus()返回 bool,用来确认代码进程和 TEKLA 进程是否握手成功。这一步很多人忽略,结果代码跑起来没报错但也没输出,其实是根本没连上。参数上不需要额外配置,只要 TEKLA 开着且模型已打开就行。注意如果 TEKLA 是以管理员权限运行的,你的代码也要用管理员权限跑,否则连不上。
3.2 批量改图框和标题栏字段
图纸入门最实用的功能就是批量改标题栏。比如项目后期业主要求把所有图纸的设计人改成同一个名字,手动改一百张图能改到怀疑人生。用代码就是遍历图纸,找到标题栏对象,改字段。
foreach (Drawing dwg in drawings) { // 拿图纸下的所有对象 DrawingObjectEnumerator objects = dwg.GetSheet().GetObjects(); while (objects.MoveNext()) { DrawingObject obj = objects.Current; // 标题栏在 TEKLA 里通常是 Text 或 Rectangle 组合 if (obj is Text textObj) { // 按内容匹配要改的字段 if (textObj.TextString.Contains("设计人")) { textObj.TextString = "设计人:张三"; textObj.Modify(); } } } }逻辑说明:GetObjects()返回的是枚举器,用MoveNext()遍历,不是 foreach 直接遍历,这是 TEKLA API 的老式写法。Text对象改完必须调Modify(),否则只改内存不写回图纸。参数上,TextString是文本内容,匹配时建议用Contains而不是==,因为标题栏文本可能带前后空格。实际项目里我会先把所有文本打出来看一遍,确认字段格式再写匹配逻辑。
3.3 自动创建图纸视图并插入对象
比改图更进一步的是自动创建视图。比如模型里有一批梁,你想每根梁自动出一张单件图,视图方向固定。这需要用到DrawingHandler.CreateDrawings()或者更细的View创建方法。
// 假设已经拿到一根梁的 ModelObject Beam beam = ...; DrawingHandler dh = new DrawingHandler(); // 创建单件图 Drawing drawing = dh.CreateDrawings( new ArrayList { beam }, new ArrayList(), new ArrayList() )[0] as SinglePartDrawing; // 拿默认视图 View view = drawing.GetSheet().GetViews()[0]; // 在视图里插入一个文本 Text text = new Text( view, new Point(100, 100, 0), "自动生成" ); text.Insert();逻辑说明:CreateDrawings第一个参数是要出图的模型对象列表,第二个是图纸属性,第三个是图纸设置,传空数组就用默认。返回的是Drawing数组,取第一个转成SinglePartDrawing。Text构造函数第一个参数是所属视图,第二个是插入点,第三个是内容,最后必须Insert()才真正画上去。参数上,插入点坐标是视图坐标,不是模型坐标,所以要先做坐标转换。实际用的时候建议先手动出一张图,用代码把视图和对象信息打出来,照着抄参数。
4. 避坑排查:图纸开发最容易翻车的 5 个地方
4.1 现象:代码编译通过但运行报「未将对象引用设置到对象的实例」
原因:最常见的是GetSheet()返回 null。多件图或者某些特殊图纸类型没有 Sheet,直接往下取视图就炸了。
解决:每次取 Sheet 和 View 之前都判空,并且用GetViews().Length > 0确认有视图再操作。我习惯写一个SafeGetFirstView(Drawing dwg)方法,内部做完整判空,返回 null 就跳过这张图。
4.2 现象:改了图纸对象但图纸上没变化
原因:TEKLA 的图纸对象修改后需要显式调Modify(),而且有些对象在视图里是只读的,比如自动标注生成的尺寸。
解决:改完立刻调Modify(),如果还不行,检查对象是不是IsReadOnly。对于只读对象,只能删了重建,不能直接改属性。
4.3 现象:批量出图跑到一半卡死
原因:在循环里频繁调CreateDrawings且没有释放资源,TEKLA 进程内存涨得很快。另外如果模型很大,每次GetDrawings()都全量拉一遍也慢。
解决:批量操作时把模型对象先收集到一个列表,一次性调CreateDrawings传整个列表,而不是循环里一张一张建。每处理完一批调一次GC.Collect()虽然不优雅但管用。
4.4 现象:图纸坐标转换后位置还是偏
原因:视图可能被旋转或镜像过,只做平移转换不够。
解决:用ViewCoordinateSystem的TransformationToLocal做完整转换,不要自己算偏移。如果还偏,检查视图的ViewRotation属性,有些视图默认带 90 度旋转。
4.5 现象:代码在开发机上跑得好,换台机器就报找不到 DLL
原因:TEKLA 版本不一致,或者目标框架不对。开发机装的是 2023,现场装的是 2021,API 接口有差异。
解决:在项目里把 TEKLA 的 DLL 设为「复制本地」为 false,运行时从 TEKLA 安装目录加载。同时代码里用反射或者条件编译兼容不同版本,别硬编码版本号。
5. 进阶技巧:用源代码做图纸批量校验和版本对比
图纸开发做到后面,最有价值的不是出图,而是校验。比如项目要交付了,业主要求所有图纸的图号不能重复、标题栏不能为空、视图比例必须是 1:10。这些用代码扫一遍比人工翻快得多。
我一般会写一个校验脚本,把图纸信息导成表格,然后用 Python 做二次分析。C# 端只负责把数据吐出来:
// 导出图纸信息到 CSV using (StreamWriter sw = new StreamWriter("drawing_check.csv")) { sw.WriteLine("图号,图纸名,视图数,比例,标题栏设计人"); foreach (Drawing dwg in drawings) { DrawingSheet sheet = dwg.GetSheet(); if (sheet == null) continue; View[] views = sheet.GetViews(); string designer = ""; // 从文本对象里找设计人字段 DrawingObjectEnumerator objs = sheet.GetObjects(); while (objs.MoveNext()) { if (objs.Current is Text t && t.TextString.Contains("设计人")) { designer = t.TextString; } } sw.WriteLine($"{dwg.Mark},{dwg.Name},{views.Length},{views[0].ViewScale},{designer}"); } }逻辑说明:这段代码把每张图的图号、名称、视图数、第一个视图的比例、设计人字段导成 CSV。参数上ViewScale是 double 类型,直接输出就行。导出的 CSV 可以用 Excel 打开做筛选,也可以用 Python 的 pandas 做重复图号检测。实际项目里我会再加一列「最后修改时间」,用来对比两次导出的差异,快速定位哪些图被改过。
另一个实用技巧是图纸版本对比。把两次导出的 CSV 做 diff,图号相同但比例或设计人变了的,就是需要重点检查的图。这个思路比人工翻图纸靠谱得多,尤其是几百张图的交付项目。
最后说个血泪经验:图纸开发的代码一定要加日志,每处理一张图就写一行「已处理图号 XXX」,不然跑到一半崩了,你根本不知道崩在哪张图上。我现在的习惯是日志和 CSV 同时输出,日志看进度,CSV 看结果。希望帮到你。
本文还有配套的精品资源,点击获取