03-SymbolTable符号表操作教程
第三章:SymbolTable符号表操作教程
3.1 符号表基础概念
3.1.1 什么是符号表
在AutoCAD数据库中,符号表(Symbol Table)是一种特殊的容器对象,用于存储和管理各种定义信息。每个符号表包含多个符号表记录(Symbol Table Record),每个记录代表一个具体的定义,如图层定义、块定义、线型定义等。
符号表的设计类似于数据库中的表和记录的关系:
- 符号表(Symbol Table):相当于数据库中的表
- 符号表记录(Symbol Table Record):相当于表中的记录
- 记录名称(Name):相当于记录的主键
AutoCAD数据库中共有九个符号表,它们在数据库创建时就自动存在,不能被删除或添加新的符号表。
3.1.2 九大符号表详解
1. BlockTable(块表)
块表是最重要的符号表,存储所有的块定义。每个BlockTableRecord代表一个块定义,包含组成该块的所有图元。特别的是,模型空间(ModelSpace)和图纸空间(PaperSpace)也是块表记录。
BlockTable
├── *Model_Space(模型空间)
├── *Paper_Space(默认图纸空间)
├── *Paper_Space0(布局1的图纸空间)
├── 自定义块1
├── 自定义块2
└── ...
2. LayerTable(图层表)
图层表存储所有的图层定义。每个LayerTableRecord代表一个图层,包含图层的名称、颜色、线型、线宽等属性。
LayerTable
├── 0(默认图层,不可删除)
├── Defpoints(标注定义点图层)
├── 自定义图层1
└── ...
3. LinetypeTable(线型表)
线型表存储所有的线型定义。每个LinetypeTableRecord代表一种线型模式。
LinetypeTable
├── Continuous(连续线,默认)
├── ByLayer(随层)
├── ByBlock(随块)
├── DASHED(虚线)
└── ...
4. TextStyleTable(文字样式表)
文字样式表存储所有的文字样式定义。每个TextStyleTableRecord定义了字体、高度、宽度因子等属性。
TextStyleTable
├── Standard(标准样式)
├── Annotative(注释性样式)
└── ...
5. DimStyleTable(标注样式表)
标注样式表存储所有的标注样式定义。每个DimStyleTableRecord定义了标注的各种参数。
DimStyleTable
├── Standard(标准样式)
├── Annotative(注释性样式)
└── ...
6. RegAppTable(注册应用程序表)
注册应用程序表存储所有注册的应用程序名称,用于扩展数据(XData)的管理。
RegAppTable
├── ACAD(AutoCAD)
├── 自定义应用程序名
└── ...
7. UcsTable(用户坐标系表)
用户坐标系表存储所有的用户坐标系定义。每个UcsTableRecord定义了一个坐标系的原点和轴方向。
8. ViewTable(视图表)
视图表存储所有命名视图的定义。每个ViewTableRecord保存了视图的位置、范围等信息。
9. ViewportTable(视口表)
视口表存储视口配置信息。每个ViewportTableRecord定义了一个视口的配置。
3.1.3 CAD原生符号表操作的问题
在使用CAD原生API操作符号表时,存在以下问题:
问题1:符号表和记录是分离的
在CAD的API中,符号表和符号表记录在类型上是独立的,没有直接的关联关系:
// 原生API的问题:需要手动关联符号表和记录
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
ObjectId btrId = bt[BlockTableRecord.ModelSpace];
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
问题2:类型不统一
不同的符号表需要使用不同的类型,但操作方式类似:
// 操作块表
BlockTable bt = tr.GetObject(db.BlockTableId, ...) as BlockTable;
BlockTableRecord btr = ...
// 操作图层表
LayerTable lt = tr.GetObject(db.LayerTableId, ...) as LayerTable;
LayerTableRecord ltr = ...
// 代码重复度高
问题3:添加记录步骤繁琐
每次添加符号表记录都需要多个步骤:
// 1. 创建记录
var ltr = new LayerTableRecord();
ltr.Name = "MyLayer";
// 2. 打开符号表写模式
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForWrite) as LayerTable;
// 3. 添加记录
ObjectId id = lt.Add(ltr);
// 4. 添加到事务
tr.AddNewlyCreatedDBObject(ltr, true);
3.2 IFoxCAD的SymbolTable类
3.2.1 SymbolTable类的设计理念
IFoxCAD的SymbolTable类解决了上述问题,它的设计理念是:
- 统一接口:使用泛型类统一处理所有符号表
- 简化操作:封装常用操作,减少样板代码
- 类型安全:利用泛型确保类型正确
- 链式调用:支持流畅的API设计
3.2.2 SymbolTable类的结构
public class SymbolTable<TTable, TRecord> : IEnumerable<ObjectId>
where TTable : SymbolTable
where TRecord : SymbolTableRecord, new()
{
// 属性
public TTable CurrentSymbolTable { get; } // 当前符号表对象
internal Database Database { get; } // 数据库对象
// 索引器
public ObjectId this[string key] { get; } // 通过名称获取记录ID
// 判断方法
public bool Has(string key); // 判断记录是否存在
public bool Has(ObjectId objectId); // 判断ID是否有效
// 添加方法
public ObjectId Add(TRecord record); // 添加记录对象
public ObjectId Add(string name, Action<TRecord>? action = null); // 添加命名记录
public ObjectId AddOrChange(string name, Action<TRecord> action); // 添加或修改
// 删除方法
public void Remove(string name); // 按名称删除
public void Remove(ObjectId id); // 按ID删除
// 修改方法
public void Change(string name, Action<TRecord> action); // 按名称修改
public void Change(ObjectId id, Action<TRecord> action); // 按ID修改
// 获取方法
public TRecord? GetRecord(ObjectId id, ...); // 获取记录对象
public TRecord? GetRecord(string name, ...); // 获取记录对象
public IEnumerable<TRecord> GetRecords(); // 获取所有记录
public IEnumerable<string> GetRecordNames(); // 获取所有记录名称
// 遍历方法
public void ForEach(Action<TRecord> task, ...); // 遍历执行
}
3.2.3 通过DBTrans访问符号表
DBTrans为每个符号表都提供了对应的属性,返回泛型化的SymbolTable对象:
using var tr = new DBTrans();
// 访问各种符号表
var blockTable = tr.BlockTable; // SymbolTable<BlockTable, BlockTableRecord>
var layerTable = tr.LayerTable; // SymbolTable<LayerTable, LayerTableRecord>
var linetypeTable = tr.LinetypeTable; // SymbolTable<LinetypeTable, LinetypeTableRecord>
var textStyleTable = tr.TextStyleTable; // SymbolTable<TextStyleTable, TextStyleTableRecord>
var dimStyleTable = tr.DimStyleTable; // SymbolTable<DimStyleTable, DimStyleTableRecord>
var regAppTable = tr.RegAppTable; // SymbolTable<RegAppTable, RegAppTableRecord>
var ucsTable = tr.UcsTable; // SymbolTable<UcsTable, UcsTableRecord>
var viewTable = tr.ViewTable; // SymbolTable<ViewTable, ViewTableRecord>
var viewportTable = tr.ViewportTable; // SymbolTable<ViewportTable, ViewportTableRecord>
3.3 索引器与Has方法
3.3.1 索引器的使用
SymbolTable提供了索引器,可以通过名称获取符号表记录的ObjectId:
using var tr = new DBTrans();
// 获取图层的ID
ObjectId layerId = tr.LayerTable["0"]; // 获取默认图层的ID
// 获取块定义的ID
ObjectId blockId = tr.BlockTable["MyBlock"];
// 如果不存在,返回ObjectId.Null
ObjectId notExistId = tr.LayerTable["NotExist"];
if (notExistId.IsNull)
{
tr.Editor?.WriteMessage("\n记录不存在!");
}
索引器的实现很简单:
public ObjectId this[string key] => Has(key) ? CurrentSymbolTable[key] : ObjectId.Null;
3.3.2 Has方法的使用
Has方法用于检查符号表记录是否存在:
using var tr = new DBTrans();
// 检查图层是否存在
if (tr.LayerTable.Has("MyLayer"))
{
tr.Editor?.WriteMessage("\n图层存在");
}
// 检查块定义是否存在
if (tr.BlockTable.Has("MyBlock"))
{
tr.Editor?.WriteMessage("\n块定义存在");
}
// 也可以通过ID检查
ObjectId someId = GetSomeObjectId();
if (tr.LayerTable.Has(someId))
{
tr.Editor?.WriteMessage("\n这个ID属于图层表");
}
Has方法的实现利用了底层符号表的Has方法:
public bool Has(string key)
{
return CurrentSymbolTable.Has(key);
}
public bool Has(ObjectId objectId)
{
return CurrentSymbolTable.Has(objectId);
}
3.4 添加符号表记录
3.4.1 Add方法详解
SymbolTable提供了多种Add方法来添加符号表记录。
方法1:添加已创建的记录对象
public ObjectId Add(TRecord record)
使用示例:
using var tr = new DBTrans();
// 创建图层对象
var layer = new LayerTableRecord();
layer.Name = "MyLayer";
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 1);
// 添加到图层表
ObjectId layerId = tr.LayerTable.Add(layer);
方法2:使用名称和委托添加
public ObjectId Add(string name, Action<TRecord>? action = null)
这是最常用的方法,它会自动创建记录对象,设置名称,并执行配置委托:
using var tr = new DBTrans();
// 简单添加(只指定名称)
tr.LayerTable.Add("Layer1");
// 添加并配置
tr.LayerTable.Add("Layer2", layer =>
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 2);
layer.LineWeight = LineWeight.LineWeight050;
layer.Description = "这是第二个图层";
});
如果记录已存在,Add方法会直接返回现有记录的ID,不会重复添加:
using var tr = new DBTrans();
// 第一次添加
ObjectId id1 = tr.LayerTable.Add("MyLayer");
// 第二次添加(相同名称)
ObjectId id2 = tr.LayerTable.Add("MyLayer");
// id1 == id2,不会创建新记录
3.4.2 AddOrChange方法
AddOrChange方法会在记录不存在时添加,存在时修改:
public ObjectId AddOrChange(string name, Action<TRecord> action)
使用示例:
using var tr = new DBTrans();
// 确保图层存在并设置属性
// 如果不存在则创建,如果存在则修改
tr.LayerTable.AddOrChange("MyLayer", layer =>
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 3);
layer.IsOff = false;
layer.IsFrozen = false;
});
3.4.3 块表的特殊处理
块表的添加有一些特殊之处,因为我们通常需要在块定义中添加图元:
using var tr = new DBTrans();
// 创建块定义
tr.BlockTable.Add("MyBlock", btr =>
{
// 创建块内的图元
var line = new Line(Point3d.Origin, new Point3d(10, 10, 0));
var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 5);
// 添加图元到块定义
btr.AppendEntity(line);
tr.Transaction.AddNewlyCreatedDBObject(line, true);
btr.AppendEntity(circle);
tr.Transaction.AddNewlyCreatedDBObject(circle, true);
// 可以添加属性定义
var attDef = new AttributeDefinition();
attDef.Position = new Point3d(0, -5, 0);
attDef.Tag = "NAME";
attDef.Prompt = "输入名称";
attDef.TextString = "默认值";
attDef.Height = 2.5;
btr.AppendEntity(attDef);
tr.Transaction.AddNewlyCreatedDBObject(attDef, true);
});
添加图元到模型空间
对于将图元添加到模型空间,IFoxCAD提供了更简便的扩展方法:
using var tr = new DBTrans();
// 使用扩展方法添加图元
var line = new Line(Point3d.Origin, new Point3d(100, 100, 0));
tr.CurrentSpace.AddEntity(line); // 扩展方法,自动处理事务
3.5 删除符号表记录
3.5.1 Remove方法
SymbolTable提供了Remove方法来删除符号表记录:
using var tr = new DBTrans();
// 按名称删除
tr.LayerTable.Remove("MyLayer");
// 按ID删除
ObjectId layerId = tr.LayerTable["SomeLayer"];
tr.LayerTable.Remove(layerId);
3.5.2 图层删除的特殊处理
图层的删除有特殊的限制:
- 不能删除图层"0"和"Defpoints"
- 不能删除正在使用的图层(有图元在该图层上)
- 不能删除当前图层
SymbolTable的Remove方法对图层表做了特殊处理:
if (CurrentSymbolTable is LayerTable lt)
{
// 检查是否为系统图层
if (SymbolUtilityServices.IsLayerZeroName(name) ||
SymbolUtilityServices.IsLayerDefpointsName(name))
return;
// 生成使用数据
lt.GenerateUsageData();
// 检查是否被使用
if (GetRecord(name) is not LayerTableRecord { IsUsed: false } ltr)
return;
using (ltr.ForWrite())
{
ltr.Erase();
}
return;
}
3.5.3 安全删除实践
在删除符号表记录之前,建议先检查是否可以删除:
using var tr = new DBTrans();
// 安全删除图层
string layerName = "MyLayer";
// 检查是否存在
if (!tr.LayerTable.Has(layerName))
{
tr.Editor?.WriteMessage("\n图层不存在!");
return;
}
// 获取图层记录
var layer = tr.LayerTable.GetRecord(layerName);
if (layer == null) return;
// 检查是否为系统图层
if (SymbolUtilityServices.IsLayerZeroName(layerName) ||
SymbolUtilityServices.IsLayerDefpointsName(layerName))
{
tr.Editor?.WriteMessage("\n不能删除系统图层!");
return;
}
// 尝试删除
try
{
tr.LayerTable.Remove(layerName);
tr.Editor?.WriteMessage($"\n图层 {layerName} 已删除!");
}
catch (Exception ex)
{
tr.Editor?.WriteMessage($"\n删除失败:{ex.Message}");
}
3.6 修改符号表记录
3.6.1 Change方法
SymbolTable提供了Change方法来修改符号表记录:
using var tr = new DBTrans();
// 按名称修改
tr.LayerTable.Change("MyLayer", layer =>
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 5);
layer.LineWeight = LineWeight.LineWeight100;
});
// 按ID修改
ObjectId layerId = tr.LayerTable["MyLayer"];
tr.LayerTable.Change(layerId, layer =>
{
layer.IsOff = true;
});
Change方法会自动处理写模式的打开和关闭:
public void Change(string name, Action<TRecord> action)
{
var record = GetRecord(name);
if (record is null) return;
using (record.ForWrite()) // 自动打开写模式
action.Invoke(record); // 执行修改
// 自动关闭写模式
}
3.6.2 批量修改
可以使用ForEach方法进行批量修改:
using var tr = new DBTrans();
// 将所有图层颜色改为白色
tr.LayerTable.ForEach(layer =>
{
using (layer.ForWrite())
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 7);
}
});
// 冻结所有以"Temp"开头的图层
tr.LayerTable.ForEach(layer =>
{
if (layer.Name.StartsWith("Temp"))
{
using (layer.ForWrite())
{
layer.IsFrozen = true;
}
}
});
3.6.3 条件修改
可以结合LINQ进行条件修改:
using var tr = new DBTrans();
// 获取所有红色图层并改为蓝色
var redLayers = tr.LayerTable.GetRecords()
.Where(l => l.Color.ColorIndex == 1);
foreach (var layer in redLayers)
{
using (layer.ForWrite())
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 5);
}
}
3.7 获取符号表记录
3.7.1 GetRecord方法
GetRecord方法用于获取符号表记录对象:
using var tr = new DBTrans();
// 按名称获取
LayerTableRecord? layer = tr.LayerTable.GetRecord("MyLayer");
if (layer != null)
{
tr.Editor?.WriteMessage($"\n图层颜色:{layer.Color}");
}
// 按ID获取
ObjectId layerId = tr.LayerTable["MyLayer"];
LayerTableRecord? layer2 = tr.LayerTable.GetRecord(layerId);
// 以写模式获取
LayerTableRecord? layerForWrite = tr.LayerTable.GetRecord(
"MyLayer",
OpenMode.ForWrite);
layerForWrite?.SetColor(Color.FromRgb(255, 0, 0));
3.7.2 GetRecords方法
GetRecords方法返回所有符号表记录:
using var tr = new DBTrans();
// 获取所有图层
foreach (var layer in tr.LayerTable.GetRecords())
{
tr.Editor?.WriteMessage($"\n图层:{layer.Name}, 颜色:{layer.Color.ColorIndex}");
}
// 使用LINQ筛选
var frozenLayers = tr.LayerTable.GetRecords()
.Where(l => l.IsFrozen)
.Select(l => l.Name);
tr.Editor?.WriteMessage($"\n冻结的图层:{string.Join(", ", frozenLayers)}");
3.7.3 GetRecordNames方法
GetRecordNames方法返回所有记录的名称:
using var tr = new DBTrans();
// 获取所有图层名称
var layerNames = tr.LayerTable.GetRecordNames();
tr.Editor?.WriteMessage($"\n图层列表:{string.Join(", ", layerNames)}");
// 使用过滤器获取满足条件的名称
var tempLayerNames = tr.LayerTable.GetRecordNames(
layer => layer.Name.StartsWith("Temp"));
3.7.4 从其他文件获取记录
SymbolTable提供了从其他文件复制符号表记录的方法:
using var tr = new DBTrans();
// 从外部文件复制块定义
ObjectId blockId = tr.BlockTable.GetRecordFrom(
t => t.BlockTable, // 选择块表
"C:\\Templates\\blocks.dwg", // 源文件
"MyBlock", // 记录名称
true); // 是否覆盖
// 从外部文件复制图层
ObjectId layerId = tr.LayerTable.GetRecordFrom(
t => t.LayerTable,
"C:\\Templates\\layers.dwg",
"StandardLayer",
false); // 不覆盖已存在的
3.8 遍历符号表
3.8.1 使用foreach遍历
SymbolTable实现了IEnumerable
using var tr = new DBTrans();
// 遍历所有图层ID
foreach (ObjectId id in tr.LayerTable)
{
var layer = tr.LayerTable.GetRecord(id);
if (layer != null)
{
tr.Editor?.WriteMessage($"\n{layer.Name}");
}
}
3.8.2 使用ForEach方法
ForEach方法提供了更方便的遍历方式:
基本用法
using var tr = new DBTrans();
tr.LayerTable.ForEach(layer =>
{
tr.Editor?.WriteMessage($"\n图层:{layer.Name}");
});
支持中断的遍历
using var tr = new DBTrans();
// 查找第一个红色图层
string? foundLayer = null;
tr.LayerTable.ForEach((layer, state) =>
{
if (layer.Color.ColorIndex == 1)
{
foundLayer = layer.Name;
state.Break(); // 中断遍历
}
});
if (foundLayer != null)
{
tr.Editor?.WriteMessage($"\n找到红色图层:{foundLayer}");
}
带索引的遍历
using var tr = new DBTrans();
tr.LayerTable.ForEach((layer, state, index) =>
{
tr.Editor?.WriteMessage($"\n{index}: {layer.Name}");
});
控制打开模式
using var tr = new DBTrans();
// 以写模式遍历
tr.LayerTable.ForEach(layer =>
{
layer.Description = $"更新于 {DateTime.Now}";
}, OpenMode.ForWrite);
3.8.3 LINQ查询
结合LINQ可以进行更复杂的查询:
using var tr = new DBTrans();
// 统计各颜色图层数量
var colorStats = tr.LayerTable.GetRecords()
.GroupBy(l => l.Color.ColorIndex)
.Select(g => new { Color = g.Key, Count = g.Count() });
foreach (var stat in colorStats)
{
tr.Editor?.WriteMessage($"\n颜色 {stat.Color}:{stat.Count} 个图层");
}
// 查找未使用的图层
tr.LayerTable.CurrentSymbolTable.GenerateUsageData();
var unusedLayers = tr.LayerTable.GetRecords()
.Where(l => !l.IsUsed && !l.Name.Equals("0"))
.Select(l => l.Name);
tr.Editor?.WriteMessage($"\n未使用的图层:{string.Join(", ", unusedLayers)}");
3.9 实际应用案例
3.9.1 图层管理器
public class LayerManager
{
/// <summary>
/// 创建标准图层集
/// </summary>
public static void CreateStandardLayers()
{
using var tr = new DBTrans();
// 定义标准图层
var standardLayers = new[]
{
("墙体", 1, LineWeight.LineWeight030),
("门窗", 2, LineWeight.LineWeight018),
("标注", 3, LineWeight.LineWeight009),
("文字", 4, LineWeight.LineWeight009),
("辅助线", 8, LineWeight.LineWeight000)
};
foreach (var (name, color, weight) in standardLayers)
{
tr.LayerTable.Add(name, layer =>
{
layer.Color = Color.FromColorIndex(ColorMethod.ByAci, (short)color);
layer.LineWeight = weight;
});
}
tr.Editor?.WriteMessage("\n标准图层创建完成!");
}
/// <summary>
/// 清理未使用的图层
/// </summary>
public static void CleanupUnusedLayers()
{
using var tr = new DBTrans();
// 生成使用数据
tr.LayerTable.CurrentSymbolTable.GenerateUsageData();
// 获取未使用的图层
var unusedLayers = tr.LayerTable.GetRecords()
.Where(l => !l.IsUsed &&
!SymbolUtilityServices.IsLayerZeroName(l.Name) &&
!SymbolUtilityServices.IsLayerDefpointsName(l.Name))
.Select(l => l.Name)
.ToList();
// 删除未使用的图层
foreach (var name in unusedLayers)
{
tr.LayerTable.Remove(name);
}
tr.Editor?.WriteMessage($"\n已删除 {unusedLayers.Count} 个未使用的图层");
}
/// <summary>
/// 导出图层设置
/// </summary>
public static void ExportLayerSettings(string filePath)
{
using var tr = new DBTrans();
var settings = tr.LayerTable.GetRecords()
.Select(l => new
{
Name = l.Name,
Color = l.Color.ColorIndex,
LineWeight = l.LineWeight.ToString(),
IsOff = l.IsOff,
IsFrozen = l.IsFrozen
})
.ToList();
// 导出为JSON(需要引用System.Text.Json)
var json = System.Text.Json.JsonSerializer.Serialize(settings);
System.IO.File.WriteAllText(filePath, json);
tr.Editor?.WriteMessage($"\n图层设置已导出到:{filePath}");
}
}
3.9.2 块库管理器
public class BlockLibraryManager
{
/// <summary>
/// 从外部文件导入块
/// </summary>
public static ObjectId ImportBlock(string sourceFile, string blockName)
{
using var tr = new DBTrans();
// 检查块是否已存在
if (tr.BlockTable.Has(blockName))
{
tr.Editor?.WriteMessage($"\n块 {blockName} 已存在,使用现有块");
return tr.BlockTable[blockName];
}
// 从文件导入
return tr.BlockTable.GetRecordFrom(
t => t.BlockTable,
sourceFile,
blockName,
false);
}
/// <summary>
/// 列出所有用户定义的块
/// </summary>
public static void ListUserBlocks()
{
using var tr = new DBTrans();
var userBlocks = tr.BlockTable.GetRecords()
.Where(btr => !btr.IsAnonymous &&
!btr.IsLayout &&
!btr.Name.StartsWith("*"))
.Select(btr => new
{
Name = btr.Name,
EntityCount = btr.Cast<ObjectId>().Count(),
HasAttributes = btr.HasAttributeDefinitions
});
tr.Editor?.WriteMessage("\n用户定义的块:");
foreach (var block in userBlocks)
{
tr.Editor?.WriteMessage(
$"\n {block.Name}: {block.EntityCount} 个图元" +
(block.HasAttributes ? " (含属性)" : ""));
}
}
/// <summary>
/// 清理未使用的块
/// </summary>
public static void PurgeUnusedBlocks()
{
using var tr = new DBTrans();
// 收集块参照计数
var blockRefCounts = new Dictionary<string, int>();
// 遍历模型空间
foreach (ObjectId id in tr.ModelSpace)
{
var ent = tr.GetObject<Entity>(id);
if (ent is BlockReference br)
{
var btr = tr.BlockTable.GetRecord(br.BlockTableRecord);
if (btr != null)
{
if (!blockRefCounts.ContainsKey(btr.Name))
blockRefCounts[btr.Name] = 0;
blockRefCounts[btr.Name]++;
}
}
}
// 删除未使用的块
var unusedBlocks = tr.BlockTable.GetRecords()
.Where(btr => !btr.IsAnonymous &&
!btr.IsLayout &&
!btr.Name.StartsWith("*") &&
!blockRefCounts.ContainsKey(btr.Name))
.Select(btr => btr.Name)
.ToList();
foreach (var name in unusedBlocks)
{
tr.BlockTable.Remove(name);
}
tr.Editor?.WriteMessage($"\n已清理 {unusedBlocks.Count} 个未使用的块");
}
}
3.9.3 线型和样式管理
public class StyleManager
{
/// <summary>
/// 确保必需的线型已加载
/// </summary>
public static void EnsureLinetypes()
{
using var tr = new DBTrans();
var requiredLinetypes = new[] { "DASHED", "CENTER", "HIDDEN", "PHANTOM" };
foreach (var ltName in requiredLinetypes)
{
if (!tr.LinetypeTable.Has(ltName))
{
try
{
tr.Database.LoadLineTypeFile(ltName, "acad.lin");
tr.Editor?.WriteMessage($"\n已加载线型:{ltName}");
}
catch
{
tr.Editor?.WriteMessage($"\n无法加载线型:{ltName}");
}
}
}
}
/// <summary>
/// 创建标准文字样式
/// </summary>
public static void CreateStandardTextStyles()
{
using var tr = new DBTrans();
// 创建中文文字样式
tr.TextStyleTable.Add("中文", style =>
{
style.FileName = "simhei.ttf";
style.BigFontFileName = "";
style.TextSize = 0; // 可变高度
style.XScale = 0.8;
});
// 创建英文文字样式
tr.TextStyleTable.Add("English", style =>
{
style.FileName = "romans.shx";
style.BigFontFileName = "";
style.TextSize = 0;
style.XScale = 1.0;
});
// 创建注释性文字样式
tr.TextStyleTable.Add("Annotative", style =>
{
style.FileName = "simhei.ttf";
style.Annotative = AnnotativeStates.True;
});
tr.Editor?.WriteMessage("\n标准文字样式创建完成!");
}
}
3.10 本章小结
本章我们深入学习了IFoxCAD的SymbolTable类:
- 符号表基础:理解了符号表的概念和CAD中的九大符号表
- SymbolTable类设计:学习了类的结构和通过DBTrans访问符号表的方式
- 索引器与Has方法:掌握了判断记录存在和获取记录ID的方法
- 添加记录:学习了Add和AddOrChange方法的使用
- 删除记录:理解了Remove方法及图层删除的特殊处理
- 修改记录:掌握了Change方法和批量修改技巧
- 获取记录:学习了GetRecord和GetRecords方法
- 遍历符号表:掌握了多种遍历方式
- 实际应用:通过图层管理器、块库管理器等案例巩固所学知识
SymbolTable类极大简化了符号表的操作,使我们能够用更少的代码完成更多的工作。下一章我们将学习选择集过滤器,这是CAD二次开发中的另一个重要主题。

浙公网安备 33010602011771号