Select Block based on Block Handle ID

Select Block based on Block Handle ID

conveyor1
Enthusiast Enthusiast
7,132 Views
9 Replies
Message 1 of 10

Select Block based on Block Handle ID

conveyor1
Enthusiast
Enthusiast

Does anyone know of a way to select a block in an AutoCAD drawing by it's unique block handle?  I am currently working on a program where it takes the block data out of the DWG and put it into excel for additional manipulation.  I would then like it to be sent back into the dwg with the update attribute information and dynamic block information.  i have most of this working, but it is slow.

 

The current code for putting the data back is a series of "for next" or "if then" statements to select the all autocad entities in the dwg, see if they are a dynamic block, see if it is the specific dynamic block I need to update and then update as required.  But when I have a hundred lines to update and more then a couple of hundred acadenities in the drawing, the looping takes time.

 

Do you know of a way to select only that block right off the bat?  I also will have the Block Name and it's insertion point.  I can also get any additional information from the block if required when I import the block into excel.

 

Please let me know when you can.

0 Likes
Accepted solutions (1)
7,133 Views
9 Replies
Replies (9)
Message 2 of 10

norman.yuan
Mentor
Mentor

If you know the Handle value of the target entities, you can call AcadDocument.HandleToObject([handle]). Note, you'd want to have proper exception handling code, in case the entity that had the handle previously has been erased prior to your code runs. In your case, the code would look like:

 

Private Function UpdateBlockReference (handleValue As String) As Boolean

    Dim obj As AcadObject

    Dim blk As AcadBlockReference

 

    On Error Go BAD_HANDLE

 

    Set obj=ThisDrawing.HandleToObject(handleValue)

    If TypeOf obj Is AcadBlockReference Then

        Set blk=obj

        If UCase(blk.EffectiveName)="MY_TARGET_BLOCK" Then

            '' Update this block reference

        End If

    End If

    UpdateBlockReference = True

    Exit Function

BAD_HANDLE:

    '' MsgBox "Invalid handle found!"

    UpdateBlockReference = False

End Function

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 10

conveyor1
Enthusiast
Enthusiast
Morning,

For some reason this part of the code is not working.

Set obj=ThisDrawing.HandleToObject(handleValue)

I get an error stating "object required".

I have following for code

Dim Block_Handle_ID_Tag As String
Dim obj As AcadObject
Dim sht As Object

Set sht = ActiveSheet

For Counter = RowNum To LastRow
Block_Handle_ID_Tag = sht.Cells(RowNum, 18).Value
Set obj = thisdrawing.HandleToObject(Block_Handle_ID_Tag)

Code stops at the Set statement.

Please let me know your thoughts.
0 Likes
Message 4 of 10

norman.yuan
Mentor
Mentor

You did not say, but I'd guess your code run in Excel's VBA, right?

 

If so, of course "ThisDrawing" is not valid in Excel VBA.

 

You need to replace it with the variable referring to an opened AcadDocument object.

 

For example, in your Excel VBA, you might have this kind of code to connect to AutoCAD and open a drawing:

 

Dim cadApp As AcadApplication

Dim dwg As AcadDocumen

 

Set cadApp=New AutoCAD.Application

Set dwg=cadApp.Documents.Open ("....file path/name...)

...

Then you can use "dwg" to replace "ThisDrawing" in my code sample.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 5 of 10

conveyor1
Enthusiast
Enthusiast
Thought it would be something like that. What if I already have cad and
the DWG open?
0 Likes
Message 6 of 10

norman.yuan
Mentor
Mentor
Accepted solution

Firstly, it is hardly a good workflow to automate a complicated desktop app, such as AutoCAD from another application (Excel app in your case): user unnecessarily has to face 2 applications for a task.

 

Anyway, in your Excel VBA side, if you want to update a given drawing, the usual process is to first try to find a running AutoCAD session. If found, check if the target drawing is open in AutoCAD session or not. If found, do something with the drawing. If the drawing if not found open, open it in AutoCAD. If there is no AutoCAD session, start one and then open the drawing.

 

The VBA code should look like something as following:

 

Dim cadApp As AcadApplication

Dim dwg As AcadDocument

Dim targetDwg As AcadDocument

 

On Error Resume Next

Set cadApp=GetObject(, "AutoCAD.Application")

if cadApp Is Nothing Then

    Set cadApp = CreateObject("AutoCAD.Application)

    If cadApp Is Nothing Then

        MsgBox "Cannot start AutoCAD!"

        Exit Sub[Function]

    End If

Else

    For Each dwg In cadApp.Documents

        If UCase(dwg.Name) = "C:\MYFOLDER\MYDWG.DWG" Then

            Set TargetDwg=dwg

            Exit For

        End If

    Next

End If

If targetDwg Is Nothing Then

    Set targetDwg=cadApp.Documents.Open("C:\MYFOLDER\MYDWG.DWG")

End If

'' Now you have the running AutoCAD session and the target drawing

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 7 of 10

Anonymous
Not applicable

Is there a way to give the block instance a unique name in Autocad so that I can use that unique name to reference the block instance in vba?  I understand handle but I prefer not to use it since the handle # doesn't have meaning and I don't have control over it.

0 Likes
Message 8 of 10

norman.yuan
Mentor
Mentor

It would be better for you to provide more detailed context in which "unique name" means. But let me make assumption. Say, you have a block called "WorkStation", and you insert 3 block references of of this block into drawing. Naturally, all 3 block references have name "WorkStation" shown in the Properties window. But you want give each block reference its own name, like "WorkStation 1" or "WorkStation 2" or "WorkStation 3", or simply "#1", "#2", or "#3". This extra piece of data can be either visible in drawing as required, or not visible but accessible programmatically (by code) for business reason.

 

If that is the case, AutoCAD's way of using block has already provide this functionality since its beginning of near 40 years ago: using Attribute within block. Add an attribute to the block with whatever tag you like, such as "Unique Name", "Station Number", or even "Name", and give the attribute a different value in different block reference. It the attribute is not meant for being visible and only accessed/controlled by programming code (to enforce the uniqueness, for example), you can flag the attribute as "Invisible". Also, besides Attribute, you can also attach data with unique value to block reference (and any type of entity, for that matter) as XData or ExtensionDictionary through your code. 

 

But I'd think, in most cases, attribute is what you are to use, simple, easy and basic for every CAD user.

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 9 of 10

Anonymous
Not applicable

Hello Norman. 

Your assumption of what I'm trying to do is correct.  I have a drawing with multiple block instances.  I'm trying to write vba code that finds a certain block instance to change its tag value.

 

If I name my block instances with attribute, what is an easy way to reference those block instances in vba?  From my current knowledge of autocad vba, I would need to loop through the drawing's objects until I find an object that has a name tag value tha I'm looking for.  Once found I would set that object to a acadblockrefernce object.

 

Basically I wonder if there is a vba statement similar to the statement below but uses attribute tag value instead handle value.

Set obj=ThisDrawing.HandleToObject(handleValue)

 

Thank you for your help.

0 Likes
Message 10 of 10

grobnik
Collaborator
Collaborator

Hi @Anonymous , @norman.yuan 

once you create a block with attributes you can use the code below to find your block with a wanted attribute name.

If you want modify the block in local, adding missing attributes, you can right click on block object and apply edit block in place, add attributes, save and upgrade the other same blocks.

For Each Block In Thisdrawing.ModelSpace
    If TypeOf Block Is AcadBlockReference Then
        If Block.Name = "S3886" Then ' Insert here block name
            If Block.HasAttributes = True Then
                Set MyBlock = Block
                MyAtt = MyBlock.GetAttributes
                For A = LBound(MyAtt) To UBound(MyAtt)
                    If MyAtt(A).TagString = "NAME" Then ' Name of attribute
                        NEW_NAME = "NEW_NAME"
                        MyAtt(A).TextString = NEW_NAME
                    End If
                Next
            End If
        End If
    End If
Next
Thisdrawing.Regen acAllViewports
End Sub

When you create a block with attributes inside a drawing or template,  later by VBA you will have an array coming from BlockObject.GetAttributes function.

Each attribute will have TextString and TagString properties, TAGSTRING it's the "NAME" of Attribute, and TextString it's the content, so you can check inside all BlockObject attributes value the Name, and change the value.