The basic object, then AcadObject, then AcadEntity, then the specialized specific top objects. This is the object inheritance hierarchy in autocad. Most objects contained by the document derive from the most general AcadObject. Hence most objects have those basic properties, which include Handle, ObjectName, ObjectID and OwnerID. All the graphic elements, things you can see, like lines and circles, further derive from the AcadEntity object. The quickest way to survey this in the ActiveX Reference Guide clicking on the graphical Object Model. The dwg document object itself does not inherit from AcadObject, but most of what it contains does.
TreeView and ListView controls in Visual Studio are a little changed in Visual Studio from VB6. TreeView no longer uses a key or a relationship parameter in the argument list. There is a tag property that takes the place of key. Building a hierarchy is done by saving the node to a variable, then using its Nodes.Add method to create a new node directly as a child node.
To connect TreeView click event to the ListView display, MS uses the tag property, illustrated in this link.
The handle property of all AcadObjects is a string. It is permanent from session to session. The ObjectID serves the same purpose, (perhaps it preceded the handle historically) but its a Long integer, and it may change from session to session. OwnerID is the long integer container object. There is no owner handle. Once you have the handle captured to a string, or the ID to a long integer, you convert the string or long to an object with a method from AcadDocument, HandleToObject(string) or ObjectIDToObject(long). I keep Option Strict On to be constantly reminded when I am trying to pass variables from one type to another.
HandleToObject returns a generic object. But if it has a handle, its an AcadObject. So it can be immediately converted to AcadObject. In general, non-graphic elements derive from AcadObject only, and graphic elements derive from both AcadObject and AcadEntity. Everything in the drawing including Blocks collection and ModelSpace derive from AcadObject.
To further identify what type of object you have, use VB method TypeName and TypeOf
Dim obj As Object Dim acad_obj As AcadObject obj = acadDoc.HandleToObject(strhandle) acad_obj = CType(obj, AcadObject) Debug.Print(TypeName(obj))
Will return the typename and
Case TypeOf acad_obj Is AcadBlock MsgBox("AcadBlock") blk = CType(obj, AcadBlock) Debug.Print(blk.Name & " " & blk.Count.ToString)
TypeOf will provide a boolean true or false to convert obj to its most specific type so you can use those methods, such as Name of the Block.
To populate a TreeView with an unknown number of levels, a recursive function is made with the parent node passed as one of the parameters.
If you are looking at a Block structure, the top level is a Block, and the embedded blocks are BlockReference.
ModelSpace and PaperSpace are blocks in the Blocks collection, they are also provided as shortcut properties of the Document, so they can be found either way, but usually using the property of the Document.
Button6 is the Block button on the form, it should say Blocks, it gets the entire Blocks collection. clicking on a node in the tree loads one level into ListView.
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click Connect_acad() ListView1.Clear() Dim acadblks As AcadBlocks Dim blk As AcadBlock acadblks = acadDoc.Blocks Dim strhandle As String strhandle = acadblks.Handle listview_by_handle(strhandle) 'start treeview TreeView1.Nodes.Clear() Dim rootnode As TreeNode rootnode = New TreeNode(acadblks.ObjectName) rootnode.Tag = acadblks.Handle TreeView1.Nodes.Add(rootnode) For Each blk In acadblks pop_tree(blk, rootnode) Next End Sub
ListViewByHandle is used to get the whole Blocks collection but its also called by a click event in the Tree to load the item selected. It has to have a fairly comprehensive Select Case to handle entities, blocks, blockrefs and block collection. I don’t try to do any levels in the ListView, so for instance, if you click on a block, it writes the block handle, name etc on the first line, then all the first level constituents under it.
Sub listview_by_handle(strhandle As String) ListView1.Clear() Dim item As ListViewItem Dim obj As Object Dim acad_obj As AcadObject Dim blk As AcadBlock Dim blkref As AcadBlockReference Dim acadblks As AcadBlocks With ListView1 .Size = New Size(850, 500) .Columns.Add("ObjectName", 180) .Columns.Add("TypeName", 180) .Columns.Add("ObjectID", 100) .Columns.Add("OwnerID", 100) .Columns.Add("Handle", 100) .Columns.Add("NAME", 180) .View = View.Details End With obj = acadDoc.HandleToObject(strhandle) ' Debug.Print(TypeName(obj)) acad_obj = CType(obj, AcadObject) item = New ListViewItem(acad_obj.ObjectName) item.SubItems.Add(TypeName(acad_obj)) item.SubItems.Add(CType(acad_obj.ObjectID, String)) item.SubItems.Add(CType(acad_obj.OwnerID, String)) item.SubItems.Add(acad_obj.Handle) Select Case True Case TypeOf acad_obj Is AcadBlocks ' MsgBox("AcadBlocks") acadblks = acadDoc.Blocks item.SubItems.Add("") ListView1.Items.Add(item) For Each blk In acadblks item = New ListViewItem(blk.ObjectName) item.SubItems.Add(TypeName(blk)) item.SubItems.Add(CType(blk.ObjectID, String)) item.SubItems.Add(CType(blk.OwnerID, String)) item.SubItems.Add(blk.Handle) item.SubItems.Add(blk.Name) ListView1.Items.Add(item) Next Case TypeOf acad_obj Is AcadBlock 'MsgBox("AcadBlock") blk = CType(obj, AcadBlock) Debug.Print(blk.Name & " " & blk.Count.ToString) item.SubItems.Add(blk.Name) ListView1.Items.Add(item) For Each acad_obj In blk item = New ListViewItem(acad_obj.ObjectName) item.SubItems.Add(TypeName(acad_obj)) item.SubItems.Add(CType(acad_obj.ObjectID, String)) item.SubItems.Add(CType(acad_obj.OwnerID, String)) item.SubItems.Add(acad_obj.Handle) If TypeOf acad_obj Is AcadBlockReference Then blkref = CType(acad_obj, AcadBlockReference) item.SubItems.Add(blkref.Name) Else item.SubItems.Add("") End If ListView1.Items.Add(item) Next Case TypeOf acad_obj Is AcadBlockReference 'MsgBox("AcadBlockReference") blkref = CType(obj, AcadBlockReference) Debug.Print("blkreference " & blkref.Name) item.SubItems.Add(blkref.Name) ListView1.Items.Add(item) Case TypeOf acad_obj Is AcadEntity 'MsgBox("AcadEntity") ListView1.Items.Add(item) End Select End Sub
pop_tree is the recursive routine that makes the tree. It passes a block type parameter and the node that is parent to the block. It immediately adds a node for the block, then it surveys the block and if the constituent is a blockreference, it recurses using the new node as parent. if the constituent is not a block, it creates a new node and makes the entry. it uses the tag to save the handle so when the tree is clicked, the handle is retrieved, and the listview can be populated from the handle.
Sub pop_tree(ByVal blk As AcadBlock, ByVal parentnode As TreeNode) Dim acad_ent As AcadEntity Dim anode As New TreeNode anode = parentnode.Nodes.Add(blk.Name) anode.Tag = blk.Handle For Each acad_ent In blk If TypeOf acad_ent Is AcadBlockReference Then Dim blkref As AcadBlockReference blkref = CType(acad_ent, AcadBlockReference) blk = acadDoc.Blocks.Item(blkref.Name) pop_tree(blk, anode) Else Dim newnode As New TreeNode newnode = anode.Nodes.Add(acad_ent.ObjectName) newnode.Tag = acad_ent.Handle End If Next End Sub
the treeview mouseclick event
Private Sub TreeView1_NodeMouseClick(sender As Object, e As TreeNodeMouseClickEventArgs) Handles TreeView1.NodeMouseClick Dim newSelected As TreeNode = e.Node 'Dim newSelected As TreeNode = TreeView1.SelectedNode Dim strhandle As String strhandle = CType(newSelected.Tag, String) listview_by_handle(strhandle) End Sub End Class