autoCAD 创建和编辑AutoCAD图元

用户可以创建的对象的范围,从简单的直线、圆到复杂的样条曲线、椭圆和关联填充区域。通常,用户使用 AppendEntity 函数添加对象到中一个 BlockTableRecord 对象中。对象创建后,就可以修改对象的像图层、颜色和线型之类的属性。

图形数据库与其它数据库程序相似,可以认为在模型空间中的一个直线对象就相当于一条表记录,模型空间就相当于数据为表。在使用数据库时,必须在使用它们之前打开和关闭记录。与存储在数据库中的对象不同的是,需要使用 GetObject 函数从数据库中获取对象,然后定义你想怎样使用对象。

本节主题
打开和关闭对象
创建对象
使用选择集
编辑命名和二维对象
使用图层,颜色和线型
保存和恢复图层状态
向图形中添加文字

打开和关闭对象

使用ObjectIds
使用事务管理器处理事务
在没有事务管理器时打开和关闭对象
升级和降级打开的对象

使用ObjectIds

包含在数据库中的每个对象都被指定了几个唯一编号。使用独特的方式访问对象的方法有:

  • 图元句柄
  • ObjectId
  • 实例指针

大多数公共方法都是通过 ObjectID 访问对象的。如果你的工程使用了COm Interop 和托管 .NET API,ObjectID 也可以很好的工作。如果创建了自定义的 AutoLISP 函数,就可以需要使用图元句柄了。

句柄在 AutoCAD 进程之间是不变的,如果需要输出图形信息到外部文件,可能稍后又需要用它更新图形,那么使用句柄是访问对象最好的方式。数据库中对象的 ObjectID 仅当数据库被加载到内存中后才存在。一旦数据库关闭了,对象的 ObjectID 就不再存在并且下次数据库再打开时,同一对象的 ObjectID 可能会不同了。

获取对象 ID

当使用对象时,打开对象用于查询和编辑它之前,首先必须获得对象的ID。当图形打开后,一个对象 ID 被赋值给数据库中的一个现有对象,一个新对象在它们首次创建时被赋值对象 ID。对象 ID 通常用于获取数据库中的现有对象:

  • 利用 Database 对象的成员属性,像 CLayer 用于获取当前图层的对象 ID。
  • 遍历符号表,像图层符号表.

打开对象

只要获得了对象 ID,GetObject 函数就可以根据特定的对象 ID 打开指定对象。一个对象可以用以下几种模式打开:

  • Read. 以只读的方式打开对象。
  • Write. 如果对象没有被打开,以写的方式打开对象。
  • Notify. 当对象关闭,以只读或可写方式打开对象时以通知的方式打开对象,但对象打开后不通知。

用户应该以这一种模式打开一个对象,这种模式使访问这个对象有最好的状态。以可写方式打开对象比创建一个可撤消记录需要更多额外的开销。如果你不确定对象是否是你想打开后用于操作的对象,就应该以只读方式打开,然后使用 UpgradeOpen 方法把模式从只读模式升级为可写模式。

GetObject 和 Open 函数都返回一个对象。在一些程序语言中,需要根据被赋值的变量值转换返回值。如果使用的是 VB.NET,就不需要担心转换返回值,因为它自己做这么做。下面示例展示为当前数据库的零层获得 LayerTableRecord。

下面的示例在事务不再需要后手工销毁它。

Dim acCurDb As Document = Application.DocumentManager.MdiActiveDocument.Database
Dim acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
 
Dim acLyrTblRec As LayerTableRecord
acLyrTblRec = acTrans.GetObject(acCurDb.LayerZero, OpenMode.ForRead)
 
acTrans.Dispose()

下面的示例使用 Using 语句在事务不再需要后销毁。Using 语句是首选的代码样式。

Dim acCurDb As Document = Application.DocumentManager.MdiActiveDocument.Database
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
    Dim acLyrTblRec As LayerTableRecord
    acLyrTblRec = acTrans.GetObject(acCurDb.LayerZero, OpenMode.ForRead)
End Using

使用事务管理器处理事务

事务是用于将多个对象的多个操作一起当作一个简单的操作。事务是通过事务管理器启动和管理的。只要事务启动了,就可以使用 GetObject 函数打开对象。

当用 GetObject 打开使用的对象时,事务管理器会追踪对对象所做的修改。任何创建和添加到数据库的新对象,最好使用 AddNewlyCreatedDBObject 函数将其添加到事务中。一旦对象完成编辑或添加到数据库,应该保存对数据库所做的修改并关闭所有打开的对象,可以使用事务管理器创建的事务对象的 Commit 函数完成此操作。只要完成一个事务,就要用 Dispose 函数关闭事务。

开始新事务并打开对象
提交与回滚更改
嵌套事务

开始新事务并打开对象

事务管理器是从当前 Database 的 TransactionManager 属性访问的。一旦对事务管理器进行了引用,就可以使用 StartTransaction 方法启动一个新事务。StartTransaction 会创建一个 Transaction 对象的实例并允许用户使用 GetObject 方法打开对象。

在事务结束的时候,所有在事务打开期间打开的对象都会被关闭。若要结束事务,请调用 Transaction 对象的 Dispose 方法。如果利用关键字 Using 和 End 表示事务的启动和结束,就不需要调用 Dispose 方法。

在 Transaction 销毁前,应用使用 Commit 方法提交所有的更改。如果 Transaction 在销毁前更改没有被提交,所有的修改都会回滚到先前 Transaction 启动时状态。

同时可以启动多个事务。活动事务的数量可以通过检索 TransactionManager 对象的 NumberOfActiveTransactions 属性得到,而最近创建的事务可以通过 TopTransaction 属性检索到。

事务可以由一个嵌套到另一个中,以回滚某些程序执行期间所做的修改。

查询对象

下面示例演示如何在事务内部打开和读取对象。用户使用 GetObject 方法首先打开 BlockTable ,然后打模型空间记录。

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
 
<CommandMethod("OpenTransactionManager")> _
Public Sub OpenTransactionManager()
  '' 获得当前文档和数据库   Get the current document and database
  Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  Dim acCurDb As Database = acDoc.Database
 
  ''启动一个事务   Start a transaction
  Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
 
      '' 以只读方式打开块表   Open the Block table for read
      Dim acBlkTbl As BlockTable
      acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
 
      '' 以只读方式打开模型空间的块表记录    Open the Block table record Model space for read
      Dim acBlkTblRec As BlockTableRecord
      acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), _
                                      OpenMode.ForRead)
 
      '' 遍历块表记录    Step through the Block table record
      For Each acObjId As ObjectId In acBlkTblRec
          acDoc.Editor.WriteMessage(vbLf & "DXF name: " & acObjId.ObjectClass().DxfName)
          acDoc.Editor.WriteMessage(vbLf & "ObjectID: " & acObjId.ToString())
          acDoc.Editor.WriteMessage(vbLf & "Handle: " & acObjId.Handle.ToString())
          acDoc.Editor.WriteMessage(vbLf)
      Next
 
      '' 销毁事务  Dispose of the transaction
  End Using
End Sub

提交与回滚更改

在使用事务处理的时候,用户能够决定什么时候将修改过的对象保存到图形数据库中。在一个事务内使用 Commit 方法保存一个对象已完成的修改。如果你的程序遇到了一个错误,就可以使用 Abort 方法回滚一个事务内所有的修改。

如果在没有调用 Commit 之前调用了 Dispose 方法,事务内所有的修改都会被回滚。无论 Commit 或 Abort 是否被调用,都必须调用 Dispose 以标示事务的结束。如果 transaction 对象是以 Using 语句开始,就不必调用 Dispose。

'' 提交事务内完成的修改  Commit the changes made within the transaction
<transaction>.Commit()
 
'' 终止事务并回滚到先前的状态     Abort the transaction and rollback to the previous state
<transaction>.Abort()

嵌套事务

事务可以由一个嵌套到另一个中。 外部的事务能够撤消你的程序所做的所有修改而内部事务仅仅能撤消部分修改。当你使用嵌套事务时,启动顶部事务也就等于启动外部事务。

当启动新事务时,它们也被添加进了前一个事务中。嵌套事务必须按与他们创建顺序相反的顺序提交或终止事务。因此,如果你有三个事务,在关闭第三个前就必须先关闭第三个或者说是最里面的一个,最后关闭第一个。如果终止了第一个事务,通过三个事务所做的修改都会撤消。

下面的插图显示在嵌套时事务如何出现。

 

 

使用嵌套事务创建和修改对象

下面演示使用三个事务创建一个圆和直线对象,然后修改他们的颜色。圆的颜色将在第二个和第三个事务中修改,但是因为第三个事务被终止了,所以仅有第一个和第二个事务所做的修改被保存到数据库中。另外,当事务被创建和关闭时,活动事务的数量将会输出到命令行窗口中。

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
 
<CommandMethod("NestedTransactions")> _
Public Sub NestedTransactions()
  '' 获得当前文档和数据库   Get the current document and database
  Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  Dim acCurDb As Database = acDoc.Database
 
  '' 创建对事务管理器的引用   Create a reference to the Transaction Manager
  Dim acTransMgr As Autodesk.AutoCAD.DatabaseServices.TransactionManager
  acTransMgr = acCurDb.TransactionManager
 
  '' 创建一个新的事务   Create a new transaction
  Using acTrans1 As Transaction = acTransMgr.StartTransaction()
 
      '' 输出当前活动事务的数量   Print the current number of active transactions
      acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
                                acTransMgr.NumberOfActiveTransactions.ToString())
 
      '' 以只读方式打开块表   Open the Block table for read
      Dim acBlkTbl As BlockTable
      acBlkTbl = acTrans1.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
 
      '' 以写方式打开模型空间块表记录   Open the Block table record Model space for write
      Dim acBlkTblRec As BlockTableRecord
      acBlkTblRec = acTrans1.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), _
                                       OpenMode.ForWrite)
 
      '' 创建一个半径为3圆心在5,5的圆    Create a circle with a radius of 3 at 5,5
      Dim acCirc As Circle = New Circle()
      acCirc.SetDatabaseDefaults()
      acCirc.Center = New Point3d(5, 5, 0)
      acCirc.Radius = 3
 
      '' 添加新对象到模型空间和事务中   Add the new object to Model space and the transaction
      acBlkTblRec.AppendEntity(acCirc)
      acTrans1.AddNewlyCreatedDBObject(acCirc, True)
 
      '' 创建第二个事务   Create the second transaction
      Using acTrans2 As Transaction = acTransMgr.StartTransaction()
 
          acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
                                    acTransMgr.NumberOfActiveTransactions.ToString())
 
          '' 修改圆的颜色   Change the circle's color
          acCirc.ColorIndex = 5
 
          '' Get the object that was added to Transaction 1 and set it to the color 5
          Dim acLine As Line = New Line(New Point3d(2, 5, 0), New Point3d(10, 7, 0))
          acLine.SetDatabaseDefaults()
          acLine.ColorIndex = 3
 
          '' 添加新对象到模型空间和事务中   Add the new object to Model space and the transaction
          acBlkTblRec.AppendEntity(acLine)
          acTrans2.AddNewlyCreatedDBObject(acLine, True)
 
          '' 创建第三个事务   Create the third transaction
          Using acTrans3 As Transaction = acTransMgr.StartTransaction()
 
              acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
                                        acTransMgr.NumberOfActiveTransactions.ToString())
 
              '' 修改圆的颜色   Change the circle's color
              acCirc.ColorIndex = 3
 
              '' 更新图形的显示   Update the display of the drawing
              acDoc.Editor.WriteMessage(vbLf)
              acDoc.Editor.Regen()
 
              '' 请求保留或放弃第三个事务所做修改     Request to keep or discard the changes in the third transaction
              Dim pKeyOpts As PromptKeywordOptions = New PromptKeywordOptions("")
              pKeyOpts.Message = vbLf & "Keep color change "
              pKeyOpts.Keywords.Add("Yes")
              pKeyOpts.Keywords.Add("No")
              pKeyOpts.Keywords.Default = "No"
              pKeyOpts.AllowNone = True
 
              Dim pKeyRes As PromptResult = acDoc.Editor.GetKeywords(pKeyOpts)
 
              If pKeyRes.StringResult = "No" Then
                  '' 放弃事务 3中所做修改   Discard the changes in transaction 3
                  acTrans3.Abort()
              Else
                  '' 保存事务3中所做修改    Save the changes in transaction 3
                  acTrans3.Commit()
              End If
 
              '' 销毁事务   Dispose the transaction
          End Using
 
          acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
                                    acTransMgr.NumberOfActiveTransactions.ToString())
 
          '' 保留事务 2所做修改   Keep the changes to transaction 2
          acTrans2.Commit()
      End Using
 
      acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
                                acTransMgr.NumberOfActiveTransactions.ToString())
 
      '' 保留事务 1 所做修改    Keep the changes to transaction 1
      acTrans1.Commit()
  End Using
End Sub

在没有事务管理器时打开和关闭对象

事务使打开和使用多个对象变得很容易,但它们并不是打开和编辑对象的唯一方法。除了使用事务,也可以使用 Open 和 Close 方法打开和关闭对象。若要使用 Open 方法仍然需要获得对象 ID。和使用事务的 GetObject 方法类似,需要指定打开的模式和返回值。如果你修改了使用 Open 方法打开的对象后,可以使用 Cancel 方法回滚自对象被打开以后所做的所有修改。Cancel 必须被每一个你想回滚的对象调用。

注意对象必须成对的使用打开和关闭操作。如果在一个对象上使用了 Open 方法,就必须利用 Close 或 Cancel 方法中的一个来关闭它。若关闭对象失败,将会导致一个读访问违规并会引起 AutoCAD 的不稳定。

如果需要使用单个对象,用 Open 和 Close 方法可以减少代码行,它是与使用事务管理器相比较不得不写的代码行。可是,推荐使用事务来打开和关闭对象。

警告当使用事务的时候,不应该使用 Open 和 Close 方法,当这么做时,通过事务管理器可能无法完全的打开或关闭对象,而且可能引起 AutoCAD 崩溃。

查询对象

下面示例演示如何在没有使用事务和 GetObject 方法时打开和关闭对象。

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
 
<CommandMethod("OpenCloseObjectId")> _
Public Sub OpenCloseObjectId()
  '' 获得当前文档和数据库   Get the current document and database
  Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  Dim acCurDb As Database = acDoc.Database
 
  '' 以只读方式打开块表   Open the Block table for read
  Dim acBlkTbl As BlockTable
  acBlkTbl = acCurDb.BlockTableId.Open(OpenMode.ForRead)
 
  '' 以只读方式打开模型空间的块表记录    Open the Block table record Model space for read
  Dim acBlkTblRec As BlockTableRecord
  acBlkTblRec = acBlkTbl(BlockTableRecord.ModelSpace).Open(OpenMode.ForRead)
 
  '' 遍历块表记录    Step through the Block table record
  For Each acObjId As ObjectId In acBlkTblRec
      acDoc.Editor.WriteMessage(vbLf & "DXF name: " & acObjId.ObjectClass().DxfName)
      acDoc.Editor.WriteMessage(vbLf & "ObjectID: " & acObjId.ToString())
      acDoc.Editor.WriteMessage(vbLf & "Handle: " & acObjId.Handle.ToString())
      acDoc.Editor.WriteMessage(vbLf)
  Next
 
  '' 关闭块表记录  Close the Block table record
  acBlkTblRec.Close()
  acBlkTblRec.Dispose()
 
  '' 关闭块表     Close the Block table
  acBlkTbl.Close()
  acBlkTbl.Dispose()
End Sub

添加新对象到数据库中

本例演示如何在没有使用事务管理器时创建新对象并将其追加到模型空间中。

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
 
<CommandMethod("AddNewCircleOpenClose")> _
Public Sub AddNewCircleOpenClose()
  '' 获得当前文档和数据库   Get the current document and database
  Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  Dim acCurDb As Database = acDoc.Database
 
  '' 以只读方式打开块表   Open the Block table for read
  Dim acBlkTbl As BlockTable
  acBlkTbl = acCurDb.BlockTableId.Open(OpenMode.ForRead)
 
  '' 以写方式打开模型空间块表记录   Open the Block table record Model space for write
  Dim acBlkTblRec As BlockTableRecord
  acBlkTblRec = acBlkTbl(BlockTableRecord.ModelSpace).Open(OpenMode.ForWrite)
 
  '' 创建一个半径为3圆心在5,5的圆    Create a circle with a radius of 3 at 5,5
  Dim acCirc As Circle = New Circle()
  acCirc.SetDatabaseDefaults()
  acCirc.Center = New Point3d(5, 5, 0)
  acCirc.Radius = 3
 
  '' 添加新对象到模型空间和事务中   Add the new object to Model space and the transaction
  acBlkTblRec.AppendEntity(acCirc)
 
  ''关闭圆对象   Close the circle object
  acCirc.Close()
  acCirc.Dispose()
 
  '' 关闭块表记录  Close the Block table record
  acBlkTblRec.Close()
  acBlkTblRec.Dispose()
 
  '' 关闭块表     Close the Block table
  acBlkTbl.Close()
  acBlkTbl.Dispose()
End Sub

升级和降级打开的对象

一旦对象使用 GetObject 或 Open 方法中的任一个被打开,就可以用 UpgradeOpen 和 DowngradeOpen 方法修改当前对象的打开模式。UpgradeOpen 方法将对象的打开模式由只读变为可写,而 DowngradeOpen 将对象的打开模式由可写变为只读。不需要成对调用 DowngradeOpen 和 UpgradeOpen,因为对象的关闭和事务的销毁将充分地清除打开图元的状态。

当用户确定打开一个对象时,使用你想用于对象的模式打开对象。当你仅需要查询对象时不应以可写方式打开对象。以只读方式打开对象并查询对象的属性比以可写方式打开对象并查询对象的属性更有效率。

以可写方式打开一个对象将为对象启动一个撤销编档。撤销编档用于跟踪对象的修改,因此任何已做修改都可以回滚。如果不确定是否需要修改对象,最好的方法是以只读方式打开对象然后需要时升级为可写模式。这样将帮助你的程序减小开销。

一个当用户可能使用 UpgradeOpen 例子是,当用户查询对象看它是否符合特定条件,而且如果条件满足,那么你可以将对象模式从只读升级为可写模式以便修改它。

打开通知

同样的,如果一个对象是以通知的方式打开的并且获得了一个通知,就应该使用 UpgradeFromNotify 升级对象为可写模式。然后你应该使用 DowngradeToNotify 降级对象为通知模式。UpgradeFromNotify 和 DowngradeFromNotify 故意被保留是为了通过对象修改它自己的打开状态,所以它可以安全的修改它自己。

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
 
<CommandMethod("FreezeDoorLayer")> _
Public Sub FreezeDoorLayer()
  '' 获得当前文档和数据库   Get the current document and database
  Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  Dim acCurDb As Database = acDoc.Database
 
  ''启动一个事务   Start a transaction
  Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
 
      '' 以只读方式打开图层表   Open the Layer table for read
      Dim acLyrTbl As LayerTable
      acLyrTbl = acTrans.GetObject(acCurDb.LayerTableId, OpenMode.ForRead)
 
      '' 遍历每个图层并更些那些以"Door"开始的图层     Step through each layer and update those that start with 'Door'
      For Each acObjId As ObjectId In acLyrTbl
          '' 以只读模式打开图层表记录    Open the Layer table record for read
          Dim acLyrTblRec As LayerTableRecord
          acLyrTblRec = acTrans.GetObject(acObjId, OpenMode.ForRead)
 
          '' 检查图层名是否以"Door"开头   Check to see if the layer's name starts with 'Door' 
          If (acLyrTblRec.Name.StartsWith("Door", _
                                          StringComparison.OrdinalIgnoreCase) = True) Then
              '' 检查图层是否是当前图层,如果是这样的话,不要冻结它    Check to see if the layer is current, if so then do not freeze it
              If acLyrTblRec.ObjectId <> acCurDb.Clayer Then
                  '' 将模式从只读变为可写    Change from read to write mode
                  acLyrTblRec.UpgradeOpen()
 
                  '' 冻结图层  Freeze the layer
                  acLyrTblRec.IsFrozen = True
              End If
          End If
      Next
 
      '' 提交修改并销毁事务  Commit the changes and dispose of the transaction
      acTrans.Commit()
  End Using
End Sub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值