Code Red > .NET

First VB.NET application......ssssllllloooooowwwwww

(1/7) > >>

Jeff_M:
OK, so I finally had a chance to put my VB.NET purchase to work. A simple little application to gather & count all blocks inserted on all layers and display the results in a Treeview on a form.

After figuring how to fill the nodes of the Treeview, all went rather smoothly. That is, until I ran it. Since I'm still using Acad2002 I have to reference the COM object, and I think this is where the problems start. Anyway, my test drawing consisted of 4 layers with 3 blocks inserted a random number of times on each layer, for a grand total of 14 blocks in the drawing. Then I execute my block-count.exe from Windows Explorer and a snappy 15, or so, seconds later my form is displayed. "Hmmm...", I think to myself, "Pretty darn slow there. I wonder what it will do on a larger drawing?" So I load up a drawing with about 500 block inserts and a ton of layers (the routine searches Modelspace, so the layer count shouldn't matter), fire-up block-count.exe, and about 3 minutes later it displays the result. "AACCKK!!", this is not very good.....

So, is my slowdown caused by the COM object, or the filling of the Treeview, or just my basic lack of understanding how to do things in VB? I have never tried to do any programming outside of Lisp & VBA, so I suspect it's probably all 3......here's the pertinent code if anyone cares to see the crud I can produce:

--- Code: ---
    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        Dim objAcad As AutoCAD.AcadApplication
        Dim ThisDwg As AutoCAD.AcadDocument
        Dim oEnt As AutoCAD.AcadEntity
        Dim oBlk As AutoCAD.AcadBlockReference
        Dim sLayName As String
        Dim sBlkName As String
        Dim oNodes As TreeNodeCollection
        Dim oNodeLay As TreeNode
        Dim oNodeBlk As TreeNode
        Dim oNodeCnt As TreeNode

        objAcad = GetObject(, "autocad.application")
        ThisDwg = objAcad.ActiveDocument
        oNodes = TreeView1.Nodes
        For Each oEnt In ThisDwg.ModelSpace
            If TypeOf oEnt Is AutoCAD.AcadBlockReference Then
                oblk = oEnt
                sBlkName = oblk.Name
                sLayName = oblk.Layer
                If NodeAvailable(sLayName, oNodes) Then
                    oNodeLay = New TreeNode(sLayName)
                    TreeView1.Nodes.Add(oNodeLay)
                Else
                    oNodeLay = AvailableNode(sLayName, oNodes)
                End If
                If NodeAvailable(sBlkName, oNodeLay.Nodes) Then
                    oNodeBlk = New TreeNode(sBlkName)
                    oNodeLay.Nodes.Add(oNodeBlk)
                    oNodeCnt = New TreeNode("1")
                    oNodeBlk.Nodes.Add(oNodeCnt)
                Else
                    oNodeBlk = AvailableNode(sBlkName, oNodeLay.Nodes)
                    oNodeCnt = oNodeBlk.Nodes.Item(0)
                    oNodeCnt.Text = oNodeCnt.Text + 1
                End If
            End If
        Next
    End Sub

    'The following 2 functions derived from http://www.dotnetspider.com/technology/kb/Article1271.aspx by Mahesh
    Private Function NodeAvailable(ByVal NodeValue As String, _
                        ByVal ndNodes As TreeNodeCollection) As Boolean

        Dim ndNode As TreeNode

        For Each ndNode In ndNodes
            If ndNode.Text = NodeValue Then
                Return False
            End If
        Next

        Return True

    End Function

    Private Function AvailableNode(ByVal NodeValue As String, _
                   ByVal ndNodes As TreeNodeCollection) As TreeNode

        Dim ndNode As TreeNode

        For Each ndNode In ndNodes
            If ndNode.Text = NodeValue Then
                Return ndNode
            End If
        Next

        Return Nothing

    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Close()
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        If Button2.Text = "Expand &All" Then
            TreeView1.ExpandAll()
            Button2.Text = "Collapse &All"
        Else
            TreeView1.CollapseAll()
            Button2.Text = "Expand &All"
        End If
    End Sub

--- End code ---

Jeff_M:
For anyone who gets past that first post, I figured out how to accomplish this in VBA. The trouble is, you aren't supposed to distribute VBA macros with the treeview control in it since VBA doesn't come with it.

And yep, it's a wee bit quicker. The same drawing that took about 3 minutes to do in VB.NET took just about the blink of an eye in VBA......

So how do I let someone else use my routine? "Just Do It"? Find out why the .NET approach is so slow? Give it up because I really don't have a clue?

Anywho, here's the code tha works in VBA. You will need to add the MSTreeview Control 6.0(SP4) to your controls. Create a form with a Treeview and 2 Command buttons. Use the Captions of Button 1 as "Done" and Button2 as "Expand All".

--- Code: ---
Option Explicit

Private Sub Button2_Click()
    Dim oNode As Node
        If Button2.Caption = "Expand All" Then
            For Each oNode In TreeView1.Nodes
                oNode.Expanded = True
            Next
            Button2.Caption = "Collapse All"
        Else
            For Each oNode In TreeView1.Nodes
                oNode.Expanded = False
            Next
            Button2.Caption = "Expand All"
        End If

End Sub

Private Sub Button1_Click()
Unload Me
End Sub

Private Sub UserForm_Initialize()
        Dim oEnt As AcadEntity
        Dim oBlk As AcadBlockReference
        Dim sLayName As String
        Dim sBlkName As String
        Dim oNodes As Nodes
        Dim oNodeLay As Node
        Dim oNodeBlk As Node
        Dim oNodeCnt As Node

        Set oNodes = TreeView1.Nodes
        For Each oEnt In ThisDrawing.ModelSpace
            If TypeOf oEnt Is AcadBlockReference Then
                Set oBlk = oEnt
                sBlkName = oBlk.Name
                sLayName = oBlk.Layer
                On Error Resume Next
                Set oNodeLay = TreeView1.Nodes.Item(sLayName)
                If Err Then
                    Err.Clear
                    Set oNodeLay = TreeView1.Nodes.Add(, , sLayName, sLayName)
                End If
                Set oNodeBlk = TreeView1.Nodes.Item(sLayName & sBlkName)
                If Err Then
                    Set oNodeBlk = TreeView1.Nodes.Add(sLayName, tvwChild, sLayName & sBlkName, sBlkName)
                    Set oNodeCnt = TreeView1.Nodes.Add(sLayName & sBlkName, tvwChild, sLayName & sBlkName & "Count", "1")
                    Err.Clear
                Else
                    Set oNodeCnt = TreeView1.Nodes.Item(sLayName & sBlkName & "Count")
                    oNodeCnt.Text = oNodeCnt.Text + 1
                End If
            End If
        Next
    End Sub

--- End code ---

Keith™:
The answer is called "marshalling" ... anytime you have to access an object across threads or processes (which is what your application is doing with AutoCAD) the process slows down considerably, sometimes to the point of being painfully slow ...

Consider making it an ActiveX dll and load it with something like this in lisp:

--- Code: ---
(setq myproj (vlax-create-object "MyProject.StartupClass"))
--- End code ---


Then when you are done with your project, you can release the project with

--- Code: ---
(vlax-release-object myproj)

--- End code ---


Of course, this will require you add a class to your project and export that class so it is callable and creatable by AutoCAD .. also, your dll will need to be registered on the computer with regsvr32.exe

Not too difficult to do once you understand the basics of it ...

Jeff_M:
Thanks Keith! I thought that the dll might be a solution, but that just brought me back to the clueless part. But now that I know it is the direction to head:

Oh boy, something new to try to learn over the weekend! :)

Kerry:

--- Quote --- ... to learn over the weekend!
--- End quote ---


You young guys with good retention and unimpaired cognition make me envious  :D

The general consensus is to save the NET stuff for AC2006+ Jeff.
Keiths comments about marshalling are spot on. Translation across interfaces is a bummer.

That being said, every step IS an advancement. There is tons of sample NET stuff around unrelated to AutoCAD.
I'd be interested in knowing your thoughts on using VB.NET. I'd have thought the differences from VB6 would outweigh any syntax similarities.
I suppose not being a prolific VB'er made the choice of C# more natural for me.

Have fun with it

Regards
Kerry

Navigation

[0] Message Index

[#] Next page

Go to full version