Get block references from layout

Get block references from layout

snappyjazz
Collaborator Collaborator
1,623 Views
4 Replies
Message 1 of 5

Get block references from layout

snappyjazz
Collaborator
Collaborator

Hello,

I am writing a script that will renumber the pages(layouts) in the dwg. The page numbers are a block attribute in the title block. So I for each through the layouts, getting the block table for each layout. Then I for each through the objectid's in the block table getting the block table reference from each. Then I for each through the objectid's in the block table reference wanting to get the block reference; but this results in a system.accessviolationexception. This post refers to the block table reference as the block, but I don't know how to modify the attributes using this technique. Am I on the right path? 

 

 

#Region " Emp_RenumberPages"
    <CadRun.CommandMethod("Emp_RenumberPages")>
    Public Sub Emp_RenumberPages()
        ' Layouts are sorted by taborder during the globals.GetLayouts sub
        Initiate()

        Try
            ' Start transaction
            Dim Trans As CadDBS.Transaction = g_AcDatBas.TransactionManager.StartTransaction()
            DB.WriteLine(vbNewLine & "Class1 | ServiceCommands | Emp_RenumberPages | ")
            ' In each layout
            For Each Layt As CadDBS.Layout In g_Layouts
                Layt.TabSelected = True
                DB.WriteLine("..." & vbTab & $"Layout: {Layt.LayoutName}")
                ' Open the Block table for read
                Dim BlkTable As CadDBS.BlockTable = Trans.GetObject(Layt.Database.BlockTableId, CadDBS.OpenMode.ForRead)

                For Each TblObjID As CadDBS.ObjectId In BlkTable
                    'If Not TblObjID.ObjectClass.Name = "AcDbBlockReference" Then : Continue For : DB.WriteLine("..." & vbTab & $"Skipping block, not AcDbBlockReference: {TblObjID.ObjectClass.Name}") : End If '<-- skip if this isn't a block reference
                    'DB.WriteLine("..." & vbTab & $"Looking at block table record object handle: {MyObjId.Handle} | Old id: {MyObjId.OldId}")
                    Dim BlTblRec As CadDBS.BlockTableRecord = CType(Trans.GetObject(TblObjID, CadDBS.OpenMode.ForRead), CadDBS.BlockTableRecord)

                    For Each ObjID As CadDBS.ObjectId In BlTblRec
                        Dim MyBlockRef As CadDBS.BlockReference = CType(Trans.GetObject(ObjID, CadDBS.OpenMode.ForRead), CadDBS.BlockReference)

                        If MyBlockRef.Name.ToString.Contains("-title") Then
                            'DB.WriteLine("..." & vbTab & "Block Reference is a titleblock.")
                            DB.WriteLine("..." & vbTab & $"Block Reference Name: {MyBlockRef.Name}")

                            ' Display the tags and values of the attached attributes
                            Dim AttCol As CadDBS.AttributeCollection = MyBlockRef.AttributeCollection

                            For Each AttObjId As CadDBS.ObjectId In AttCol
                                Dim DbObj As CadDBS.DBObject = Trans.GetObject(AttObjId, CadDBS.OpenMode.ForRead)

                                Dim AttRef As CadDBS.AttributeReference = DbObj

                                DB.WriteLine("..." & vbTab & vbTab & "Tag: " & AttRef.Tag & "Value: " & AttRef.TextString)

                                ' Change the value of the attribute
                                ' AttRef.TextString = "NEW VALUE!"

                            Next
                        End If
                    Next
                Next

                DB.WriteLine(vbNewLine)

            ' Save the new object to the database
            Trans.Commit()

        Catch ex As Exception
            Return
        End Try
    End Sub

#End Region
0 Likes
Accepted solutions (1)
1,624 Views
4 Replies
Replies (4)
Message 2 of 5

_gile
Consultant
Consultant
Accepted solution

Hi,

You are not on the right path.

You have to understand the AutoCAD Database structure (see this topic). Each layout is associated with a BlockTableRecord (see this topic). A BlockTableRecord is a container for entities (graphical objects such as Line, Circle, BlockReference, ...).

So, for each paper space Layout you have to ge the associated BlockTableRecord and, for each entity in this BlockTableRecord, check if the entity is the BlockReference you're looking for.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 5

snappyjazz
Collaborator
Collaborator

@_gile

Thanks for helping. The help post about layouts and blocks says there is only one btr per layout object. That helps narrow things down. The last statement also pointed out that you can get the btr directly from the layout object. So I don't need to loop through the block table.  So I removed the blocktable loop and added the following after the Layt loop:

Dim BTR as BlockTableRecord = Trans.GetObject(Layt.BlockTableRecordId, OpenMode.ForRead)

 

The help post explaining the blocktablerecord confuses me. The bottom paragraph says BTRs other than model space or paper space were known in previous versions as block definitions and are referenced by BlockReferences. Does that mean block references replaced block definitions? I don’t understand how to access the blockreference collection BTR.BlockReferences isn’t an option for me? The help paragraph goes on to say that the BTR contains a collection of entities that can be referenced by multiple inserts… Looking at the help section for block reference, the hierarchy shows dbobject->entity->blockreference. Sounds like what I need but I can’t figure out how to access the entity collection in the BTR either. Can please you help me connect the dots? 

0 Likes
Message 4 of 5

Ed__Jobe
Mentor
Mentor

From what you know about using AutoCAD, there's just block definitions and block references. The block table holds definitions, which is a collection of entities. If the definition is the container for a layout, then it can hold block references. When you are iterating a block table record's contents, you may come across a block reference for another block table record. You can use the block reference's Name property (or EffectiveName in the case of a dynamic block) to get the name of it's block table record, or definition. So think about the relationship between a btr (definition) and reference (insert). The only difference is that .NET api uses different names.

Ed


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
How to post your code.

EESignature

Message 5 of 5

snappyjazz
Collaborator
Collaborator

I figured it out. Once you have the BTR you can loop through it as objectid. Use the object id's to set the kind of object you're looking for in my case blockreference. Thank you @_gile!

 

#Region " Emp_RenumberPages"
    <CadRun.CommandMethod("Emp_RenumberPages")>
    Public Sub Emp_RenumberPages()
        ' Layouts are sorted by taborder during the globals.GetLayouts sub
        Initiate()

        Try
            ' Start transaction
            Dim Trans As CadDBS.Transaction = g_AcDatBas.TransactionManager.StartTransaction()
            DB.WriteLine(vbNewLine & "Class1 | ServiceCommands | Emp_RenumberPages | ")
            ' In each layout
            For Each Layt As CadDBS.Layout In g_Layouts
                DB.WriteLine("..." & vbTab & $"Layout: {Layt.LayoutName}")

                ' Get the BTR of the layout.
                Dim BTR As CadDBS.BlockTableRecord = Trans.GetObject(Layt.BlockTableRecordId, CadDBS.OpenMode.ForRead)

                ' Go through each entity id
                For Each ObjID As CadDBS.ObjectId In BTR
                    ' Try establishing this entity as a block reference. Skip if it isn't
                    Dim MyBlockRef As CadDBS.BlockReference
                    Try : MyBlockRef = CType(Trans.GetObject(ObjID, CadDBS.OpenMode.ForRead), CadDBS.BlockReference) : DB.WriteLine("..." & vbTab & $"Block Reference Name: {MyBlockRef.Name}")
                    Catch ex As Exception : DB.WriteLine("..." & vbTab & $"Skipping: {ObjID}") : Continue For : End Try

                    ' Check if this block reference's name contains title
                    If MyBlockRef.Name.ToString.Contains("-title") Then
                        ' Get the attribute collection of the title block
                        Dim AttCol As CadDBS.AttributeCollection = MyBlockRef.AttributeCollection

                        ' Go through each attribute
                        For Each AttObjId As CadDBS.ObjectId In AttCol
                            ' Make a dbobject from the object id
                            Dim DbObj As CadDBS.DBObject = Trans.GetObject(AttObjId, CadDBS.OpenMode.ForRead)

                            ' Convert to atrribute reference
                            Dim AttRef As CadDBS.AttributeReference = DbObj

                            ' Display the tags and values of the attached attributes
                            DB.WriteLine("..." & vbTab & vbTab & "Tag: " & AttRef.Tag & "Value: " & AttRef.TextString)

                            ' Change the value of the attribute
                            ' AttRef.TextString = "NEW VALUE!"

                        Next
                    End If
                Next

                DB.WriteLine(vbNewLine)

            Next

            ' Save the new object to the database
            Trans.Commit()

        Catch ex As Exception
            Return
        End Try
    End Sub

#End Region

 

snappyjazz_0-1679498350844.png

 

0 Likes