Get a block object, from its name

Get a block object, from its name

george1985
Collaborator Collaborator
436 Views
8 Replies
Message 1 of 9

Get a block object, from its name

george1985
Collaborator
Collaborator

Dear Autocad ActiveX Experts,

How to get a block object (AcadBlock) from its name?


Is the only way, iteration through all blocks in the current document, and then checking if any of their names is equal to required block name?


I have 900 "normal" blocks and dynamic blocks in my .dwg file.
Thus, to search for the their AcadBlock object, can be very time consuming with upper mentioned approach (I posted the code below).

Is there some faster approach for AutoCAD ActiveX API? Without the use of AutoCAD NET API?

I would be very grateful for any kind of help. As at the moment I am quite desperate.
Thank you in advance.

' Name of the block(s) you are looking for
Dim blockName As String
blockName = "Block1" ' Change this to the desired block name


' Get the active AutoCAD document
Dim acadApp As AcadApplication
Set acadApp = Application

' Get the active drawing
Dim acadDoc As AcadDocument
Set acadDoc = acadApp.ActiveDocument

' Get the Blocks collection
Dim blocks As AcadBlocks
Set blocks = acadDoc.Blocks

' Create a collection to store the found blocks
Dim foundBlocks As Collection
Set foundBlocks = New Collection


' Iterate through all the blocks in the drawing
Dim eachBlock As AcadBlock
For Each eachBlock In blocks

  ' Check if the current block's name matches the specified name
  If UCase(eachBlock.Name) = UCase(blockName) Then
    ' Add the matching block to the foundBlocks collection
    foundBlocks.Add eachBlock
  End If

 

0 Likes
Accepted solutions (1)
437 Views
8 Replies
Replies (8)
Message 2 of 9

norman.yuan
Mentor
Mentor
Accepted solution

So, you want to know if a block DEFINITION with certain name(AcadBlock, not AcadBlockReference) exists in the drawing which may contain hundreds of them, or more.

 

I'd say looping through them to find one, would not be an issue that user would feel noticeable "slowness", unless you need to search many blocks by name with many loops inside loops. That is actually comparing strings (block names, depending how they are named, how long the string be) may cost time. So, I do not see an issue with your code when searching a single block by name (only, why saving the single block definition in a Collection?).

 

Since block definition (AcadBlock) is stored in block table, keyed by their name, it can be quickly reached by AcadDocument.Blocks(blockName), you code can be shorten and simplified (and run quickly) by 

 

public Function FindBlockDefinition(drawing As AcadDocument, blkName As String) As AcadBlock

  On Error Resume Next
  Set FindBlockDefinition = drawing.Blocks(blkName)

End Function

 

Notice that because of "On Error Resume Next", he function would returns Nothing, if a block definition with the given name does not exist. 

 

Again, Letting AutoCAD hits an error and resume to next step may or may not be noticeable fast than loop through the block table, unless there are large numbers of blocks and/or with long block names, and/or having to search in multiple loops.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 9

Ed__Jobe
Mentor
Mentor

@george1985  In addition to what @norman.yuan said, you need to realize that the AcadBlocks are already in a collection, ThisDrawing.Blocks. There is only one instance of each definition in the collection and the names are indexed, so a name search is fast. You were putting a block into a new collection. This makes me believe that you have a misunderstanding of the block's api, since there is only one AcadBlock for each block definition. When you say you have 900 blocks in a dwg, I think you mean AcadBlockReference object which are the equivalent of a lisp INSERT object when you use the LIST command. So, I think what you want to do is select a block in the dwg and use the Name property of the insert to get the AcadBlock object representing the block definition. Is that correct? From your first post, it's not clear what your process is. If so, this sample might help you.


Sub Test7()
    Dim pp As Variant
    Dim ent As AcadEntity
    Dim blk As AcadBlock
    Dim blkref As AcadBlockReference
    ThisDrawing.Utility.GetEntity ent, pp, "Select a block"
    If Not ent Is Nothing And ent.ObjectName = "AcDbBlockReference" Then
        Set blkref = ent
        Set blk = ThisDrawing.Blocks(blkref.EffectiveName) 'works on dynamic blocks too
        'do something with the blk
        MsgBox "The block's name is " & blk.Name
    End If
End Sub

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 4 of 9

george1985
Collaborator
Collaborator

I apologize for the late reply. Thank you both of you for the detailed help.

Hi @norman.yuan ,

Brilliant! Thank you very much for the 'drawing.Blocks(blkName)' solution! Indeed it is faster, then iterating through each item in drawing.Blocks.

 

There is no way to check somehow if 'drawing.Blocks.HasKey(blkName)'?
I see no such method in AcadBlocks class:

george1985_0-1747435548306.png

 

 


Hi @Ed__Jobe ,
Thank you as well for your solution.

 

I have around 900 normal (non-dynamic) + dynamic block instances (AcadBlockReference objects).

I would like to extract geometry of each of those 900 instances.
For the normal blocks, your solution works perfectly.

The issue are dynamic block instances: Autocad threats each "unique" one of them: as an individual block definition (AcadBlock object). The names of those individual block definitions are "U2", "U3", "U4"...

By "unique" I mean: dynamic block which has unique combination of its parameters (Length, Height, Rotation angle...). But not its attributes.

Because of upper mentioned individual block definition (AcadBlock object) for each unique dynamic block instance - this means that I can't use the .EffectiveName property. I have to find the unique block definition of each unique instance via .Name property.

This was the reason, why I was looking for a faster approach to get the block definition, instead of iterating through the drawing.Blocks.

 

0 Likes
Message 5 of 9

Ed__Jobe
Mentor
Mentor

First, your question regarding a Haskey method, if you ask for the key Name and if doesn’t exist, you get an error. That’s why Norman encapsulated the call in a separate function. His solution is effectively a HasKey function. If it’s there, you get a Block object. If not, you get nothing. Just test the function for return of nothing. 

Dim blk As AcadBlock
Set blk = FindBlockDefinition()
If Not blk Is Nothing Then
   'Do something with blk
Endif 



Second, if you have a dynamic block and you want the anonymous block, just use the Name property instead of the EffectiveName property. 

Third, to get the attributes , you need to reference the AcadBlockReference object and access its Attributes collection. The AcadBlock object just has a template for the attributes. 

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 6 of 9

george1985
Collaborator
Collaborator

Hi @Ed__Jobe 


Thank you very much for the detailed reply.


I guess the function encapsulation is specific to VBA. When similar is tried with .NET - the .NET function raises just an error once 'blkName' does not exist in 'drawing.Blocks'


Yes, exactly, I am using the upper suggestion by Norman 'drawing.Blocks(blkName)', where 'blkName' is obtained via 'AcadBlockReference.Name'.

Thank you very much for the shared knowledge on Attributes, and how to access them.

0 Likes
Message 7 of 9

Ed__Jobe
Mentor
Mentor

@george1985 wrote:

Hi @Ed__Jobe 


I guess the function encapsulation is specific to VBA. When similar is tried with .NET - the .NET function raises just an error once 'blkName' does not exist in 'drawing.Blocks'

 You never mentioned that you were using .net. You still need to trap the error, but you would use a try.catch statement. In one of the catch clauses, you can just ignore the error or return Nothing.

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 8 of 9

george1985
Collaborator
Collaborator

Hi @Ed__Jobe ,
Yes, that was my mistake, I apologize. I tried both the VBA and .NET.
Thank you once again for the helpful suggestion.

0 Likes
Message 9 of 9

george1985
Collaborator
Collaborator

Thank you very much once again for the help and shared knowledge, both @norman.yuan  and @Ed__Jobe 
What would we users do, without you on this forum.

If any of you is passing near Vienna, I owe you a beer.

0 Likes