×
INTELLIGENT WORK FORUMS
FOR ENGINEERING PROFESSIONALS

Log In

Come Join Us!

Are you an
Engineering professional?
Join Eng-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!
  • Students Click Here

*Eng-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Jobs

API, Assembly traversal, grab children attribute
4

API, Assembly traversal, grab children attribute

API, Assembly traversal, grab children attribute

(OP)
I am trying to do a seemingly simple task that is to be a portion of a much larger macro.  I have created several test components and assemblies.  The children of the top assy have all been assigned a custom property called "Level".  The value associated with "Level" is 0 or 1.  The function of this macro is to traverse through the children of the already open top assy, looking at the Level attribute.  It will then create and assign a Level attribute to the top assy.  The value of this attribute will be one higher than the highest of the children components.

The area I am having trouble with is grabbing the value of the attribute from the children.  I downloaded a sample macro called TraverseAssembly to help me creating this one.  The sample worked well to output the name of the children, I want to dive just a bit deeper.  Below is my code.  In bold is the line of code where I receive an error.  Any help on this would be appreciated.  Mind you I don't have much of a background in code so specific info is appreciated.
-Shaggy


Const swDocASSEMBLY = 2

Dim swApp As SldWorks.SldWorks
Dim ModelDoc As SldWorks.ModelDoc2
Dim Level As Integer
Dim strText As Variant

Sub Main()

    Dim swRootComp As SldWorks.Component2
    Dim swConf As SldWorks.configuration
    Dim FileName As String
    
    Set swApp = Application.SldWorks
    Set ModelDoc = swApp.ActiveDoc
    
    
    If Not ModelDoc Is Nothing Then
        If ModelDoc.GetType = swDocASSEMBLY Then
            'Get the active configuration
            Set swConf = ModelDoc.GetActiveConfiguration
            Set swRootComp = swConf.GetRootComponent
            'Traverse the assembly
            TraverseComponent swRootComp
        End If
    End If
    ModelDoc.AddCustomInfo3 "", Level, swCustomInfoText, ""
    ModelLevel = childlevel + 1
    ModelDoc.CustomInfo2("", Level) = ModelLevel
        
End Sub


Sub TraverseComponent(swComp As SldWorks.Component2)
    'this recursively traverses all of the components in an assembly
    Dim vChildComp                  As Variant
    Dim swChildComp                 As SldWorks.Component2
    Dim i                           As Long
    Dim childlevel                  As Long
    Dim childlevel_temp             As Long
    Dim ModDoc                      As Object   ' ModelDoc2 of child component
    Dim ModName                     As String
    

    vChildComp = swComp.GetChildren
    childlevel_temp = 0
    childlevel = 0
    For i = 0 To UBound(vChildComp)
        Set swChildComp = vChildComp(i)
        ModName = swChildComp.Name
        Set ModDoc = swChildComp.GetModelDoc()
        childlevel_temp = swChildComp.GetCustomInfoValue("", Level)
           If childlevel_temp > childlevel Then
              childlevel = childlevel_temp
           End If
    Next i
End Sub

RE: API, Assembly traversal, grab children attribute

When I build a recursive Sub or Function that does things like travers an assembly, I build the level counter into the code as one of the arguments.

RE: API, Assembly traversal, grab children attribute

3
I'm not in front of SWX right now, but it looks like the line immediately above your bolded line gets the ModelDoc2 object for the current child component.  That's the object you need to hit for the GetCustomInfoValue function.  So you would change your bolded line to:

childlevel_temp = ModDoc.GetCustomInfoValue("", Level)

Hope this gets it for you!

RE: API, Assembly traversal, grab children attribute

(OP)
handleman,
Thank you for the input.  I attempted the change that you suggested, the same issue arose.  When I ran the macro, the error popped up giving me the opportunity to debug.

Tick,
I am not quite clear what you mean.  I do not want to dig any deeper than one level.

-Shaggy

RE: API, Assembly traversal, grab children attribute

I think I found your problem.  CustomInfo values are returned as strings.  The variables you are using to retrieve the CustomInfo values are Long.

Two possible fixes:

CODE

Dim childlevel As Long
Dim childlevel_temp As Long
-OR-

CODE

childlevel_temp = cLng(swChildComp.GetCustomInfoValue("", Level))

RE: API, Assembly traversal, grab children attribute

(OP)
Tick,
I have tried both of your suggestions (the first one, I assumed you meant I should change the "Long" to "string" because both were previously dim as Long.  That didn't work.  I also tried changing the childlevel_temp as you described.  That didn't work either.

The error I get is a Run Time error 438.  The description is Object doesn't support this property or method.

I am using SW2005 if that makes a difference.

Thanks again for the assistance everyone.
-Shaggy

RE: API, Assembly traversal, grab children attribute

Sorry, just noticed something.  I believe that Level needs to be in quotes, as it is a string.  So your line would be:

CODE

childlevel_temp = cLng(swChildComp.GetCustomInfoValue("", "Level"))

Looking a bit deeper, you have a module level variable called Level that's defined as an integer.  You're also trying to use the word "Level" as a string several places without quotes around it.  So every time your macro sees the word Level without quotes it puts in the value of the integer variable "Level", which may be messing you up in a lot of ways.  For example, this line

ModelDoc.AddCustomInfo3 "", Level, swCustomInfoText, ""

adds a custom property that is named whatever the current value of Level is.  If you want to add a custom property named Level then you would need to have

ModelDoc.AddCustomInfo3 "", "Level", swCustomInfoText, ""

I'm about 99% confident that this is the main problem area.  I'm at home, so I don't have access to SW right now to verify.  My PC just doesn't have the power to run SW like my dual Xeon with 3G of ram, so it would be more aggravating than helpful.  smile

RE: API, Assembly traversal, grab children attribute

Sorry, you are correct.  I meant "String" and not "Long".  Too quick to move on after the cut-and-paste.

I think handleman has found the other half of the problem.  The name of the property is a string, and should be in quotes to be a string value.

CODE

Dim PropValue as String
Dim PropName as String
PropName = "Level"
PropValue =swChildComp.GetCustomInfoValue("", PropName)

Also keep in mind that property names are case-sensitive.

RE: API, Assembly traversal, grab children attribute

(OP)
Tick and handleman,
Thank you for your contribution.  Your input has allowed me to move forward on this macro.  However I now have a couple new issues.  I added a little msgBox so I could be sure that the macro was traversing and grabbing the child's "Level" attribute.  It is.  However when it completes the TraverseComponent sub routine I believe it loses the "knowledge" of the childlevel variable.  When it gets back into the Main() it is supposed to add 1 to the childlevel to define the ModelLevel.  It does not.  It simply thinks childlevel is zero and therefore Modellevel is 1.  Is there some special way that I need to carry that variable back into the Main()?

The second problem seems very basic and I am not sure why it isn't working.  The ModelDoc.AddCustomInfo3 "", Level, swCustomInfoNumber, "" is not working.  I can't create the new attribute in the parent.  I think it may have something to do with the children components becoming the active doc while they were being searched through.  How do I re-activate the parent doc so i can create the attribute?  I tried Modeldoc.ActivateDoc2 function.  That didn't seem to work.  I may have used it wrong however.

Below is a copy of the macro.  In bold are the areas that I believe are causing problems now.  Italicized are the areas that I changed based on your input.  Thanks again for your effort.
-Shaggy

Const swDocASSEMBLY = 2

Dim swApp As SldWorks.SldWorks
Dim ModelDoc As SldWorks.ModelDoc2
Dim strText As Variant

Sub Main()

    Dim swRootComp As SldWorks.Component2
    Dim swConf As SldWorks.configuration
    'Dim FileNum As Integer
    'Dim FS As Scripting.FileSystemObject
    Dim FileName As String
    Dim ModelLevel As Integer
    Dim childlevel As Integer
    Set swApp = Application.SldWorks
    Set ModelDoc = swApp.ActiveDoc
    
    
    If Not ModelDoc Is Nothing Then
        If ModelDoc.GetType = swDocASSEMBLY Then
            FileName = ModelDoc.GetTitle
            'Get the active configuration
            Set swConf = ModelDoc.GetActiveConfiguration
            Set swRootComp = swConf.GetRootComponent
            'Traverse the assembly
            TraverseComponent swRootComp
        End If
    End If
    'If AssySkipped = True Then
    'MsgBox ("ASSEMBLY FILE SKIPPED")
    'Else
    'MsgBox ("The Active Doc is " & ModelDoc)
    ModelDoc.AddCustomInfo3 "", "Level", swCustomInfoNumber, ""
    'MsgBox (childlevel)
    ModelLevel = (childlevel + 1)
    ModelDoc.CustomInfo2("", "Level") = ModelLevel
    MsgBox ("New Level for Parent is " & ModelLevel)
    MsgBox ("ASSEMBLY FILE NOT SKIPPED")
    'End If
        
End Sub


Sub TraverseComponent(swComp As SldWorks.Component2)
    'this recursively traverses all of the components in an assembly
    Dim vChildComp                  As Variant
    Dim swChildComp                 As SldWorks.Component2
    Dim i                           As Long
    Dim childlevel                  As String
    Dim childlevel_temp             As String
    Dim ModDoc                      As Object   ' ModelDoc2 of child component
    Dim ModName                     As String
    

    vChildComp = swComp.GetChildren
    childlevel_temp = 0
    childlevel = 0
    For i = 0 To UBound(vChildComp)
        Set swChildComp = vChildComp(i)
        ModName = swChildComp.Name
        Set ModDoc = swChildComp.GetModelDoc()
        childlevel_temp = CInt(ModDoc.GetCustomInfoValue("", "Level"))
        'MsgBox ("childlevel for " & ModName & " is " & childlevel_temp)
           If childlevel_temp > childlevel Then
              childlevel = childlevel_temp
           End If
    Next i
End Sub

RE: API, Assembly traversal, grab children attribute

Your current issue is a problem with the scope of your variables.  You have three variables that are declared at the very beginning, before any sub.  These are "Module level".  

Dim swApp As SldWorks.SldWorks
Dim ModelDoc As SldWorks.ModelDoc2
Dim strText As Variant

That means that any subroutine in the module can read or write to them.  The rest of your variables are declared inside subroutines.  Any variable declared inside a subroutine or function can only be seen by that subroutine or function.  You can declare a variable with the same name in two different subs or functions, but they won't be the same variable.  That's why your "Main" macro doesn't see the value of "childlevel".  If you want "childlevel" to be the same variable in both subs then declare it up with the other three.

I'm not sure why the AddCustomInfo3 isn't working.  I don't recall the syntax right now.  It's not an issue of the wrong model being "active".  Once you have a ModelDoc2 object it stays there until you either set the variable to some other value or it goes out of scope.  You can verify pretty easily that you still have the right one by using a line like:

MsgBox ModelDoc.GetTitle

It looks like you tried to do that with

'MsgBox ("The Active Doc is " & ModelDoc)

but it probably errored out, since the message box can't display an object.  

Good luck!

RE: API, Assembly traversal, grab children attribute

(OP)
handleman,
Thanks again for the help.  I was able to get the macro to work.  I put the declaration for childlevel at the very top.  I was able to get the macro to create the custom property by changing the ModelDoc.AddCustomInfo3 "", "Level", swCustomInfoNumber, ""   line to ...swCustomInfoText.  I am not sure however why Number didn't work.  Doesn't really seem to matter though.

I am sure I will have future questions as this is only a portion of the actual macro I am trying to create.  Your help as well as TheTick's help is greatly appreciated.

Also, I have not searched it, but what are the recommended books for learning SW API and/or Visual Basic?

-Shaggy

RE: API, Assembly traversal, grab children attribute

Sounds like you're going about it in the same way I did - a lot of not succeeding at first and trying, trying again.  The SW API help is pretty good once you have a basic understanding of VBA.  However, it looks like you're fairly new at VBA as well.  I got my VBA a little bit at a time, mostly trial and error and help files.  Perhaps someone else can suggest a resource to fill your head with VBA knowledge without having to crack it open banging it on your desk first.  smile

RE: API, Assembly traversal, grab children attribute

(OP)
Thanks handleman.

I did a search on Amazon and found a book called Automating Solidworks with Macros by Mike Spens.  I think it should clue me in a bit more.  I am presently using the SW API help quite a bit with some success.  That and downloading sample macros to see how they work.  I am brand new to VBA and I think that is where I am having the most difficulty.  But I am chugging along.

Thanks again,
-Shaggy

RE: API, Assembly traversal, grab children attribute

handleman, Tick, Shaggy

1. Is it possible to create a custom property in the other direction, by reading it from the top level assy and then traverse the assembly and adding it to every children?

2. In what way is Shaggy's TraverseComponent routine recursive?

RE: API, Assembly traversal, grab children attribute

1. Sure.  The macro would be real similar to (Shaggy's working version of) the macro above.

2. It is recursive by:

  a. Get all children of the parent component (the assembly) with the line vChildComp = swComp.GetChildren. This returns an array with all the child components.  
  b. Looping through the children with the "For" loop starting with For i = 0 To UBound(vChildComp).

RE: API, Assembly traversal, grab children attribute

Thanks, handleman.

RE: API, Assembly traversal, grab children attribute

(OP)
dogarila,
I have posted the working version of my macro for you to sample if you need it.
-Shaggy

CODE

Const swDocASSEMBLY = 2

Dim swApp As SldWorks.SldWorks
Dim ModelDoc As SldWorks.ModelDoc2
Dim childlevel As Integer
Dim strText As Variant

Sub Main()

    Dim swRootComp As SldWorks.Component2
    Dim swConf As SldWorks.configuration
    Dim ModelLevel As Integer
    Set swApp = Application.SldWorks
    Set ModelDoc = swApp.ActiveDoc
    
    
    If Not ModelDoc Is Nothing Then
        If ModelDoc.GetType = swDocASSEMBLY Then
            Set swConf = ModelDoc.GetActiveConfiguration
            Set swRootComp = swConf.GetRootComponent
            'Traverse the assembly
            TraverseComponent swRootComp
        End If
    End If
    'If AssySkipped = True Then
    'MsgBox ("ASSEMBLY FILE SKIPPED")
    'Else
    ModelDoc.AddCustomInfo3 "", "Level", swCustomInfoText, ""
    ModelLevel = (childlevel + 1)
    ModelDoc.CustomInfo2("", "Level") = ModelLevel
    MsgBox ("ASSEMBLY FILE NOT SKIPPED")
    'End If
        
End Sub


Sub TraverseComponent(swComp As SldWorks.Component2)
    'this recursively traverses all of the components in an assembly
    Dim vChildComp                  As Variant
    Dim swChildComp                 As SldWorks.Component2
    Dim childlevel_temp             As String
    Dim ModDoc                      As Object   ' ModelDoc2 of child component
    Dim ModName                     As String
    

    vChildComp = swComp.GetChildren
    childlevel_temp = 0
    childlevel = 0
    For i = 0 To UBound(vChildComp)
        Set swChildComp = vChildComp(i)
        ModName = swChildComp.Name
        Set ModDoc = swChildComp.GetModelDoc()
        childlevel_temp = CInt(ModDoc.GetCustomInfoValue("", "Level"))
           If childlevel_temp > childlevel Then
              childlevel = childlevel_temp
           End If
    Next i
End Sub

RE: API, Assembly traversal, grab children attribute

In the code above, in the TraverseComponent subroutine, in the For.. Next loop, I load a form with some custom properties, show it, do some changes in the form, save the changes and unload the form. I expect the program will return to the TraverseComponent and continue with next element. It does not do that. It just stops. I wonder why?

RE: API, Assembly traversal, grab children attribute

Try showing/hiding the form rather than loading and unloading it.  Of course, if you do that you will need a form resetting sub that resets the form to its default values.  

RE: API, Assembly traversal, grab children attribute

It doesn't stop anymore. Actually it doesn't stop at all. Shows the form. Hides the form. Shows the form, hides the form by itself until all the components in the assembly are traversed.

Now here's another question:

CODE


Option Explicit
Public docType As Integer
Public swApp As SldWorks.SldWorks
Public swModel As SldWorks.ModelDoc2
Dim returnOK As Boolean
Public Part As Object

Private Sub Main()

Dim swRootComp As SldWorks.Component2
Dim swConf As SldWorks.Configuration


Set swApp = CreateObject("SldWorks.Application")
swApp.Visible = True
Set swModel = swApp.ActiveDoc

If swModel Is Nothing Then
    Call MsgBox("A SolidWorks document needs to be loaded!", vbExclamation, "Custom Properties")  ' Display error message
    returnOK = False
    swApp.Visible = True

    End                    ' If no model currently loaded, then exit
    Else
     docType = swModel.GetType
     If (docType = swDocASSEMBLY) Then
        Set swConf = swModel.GetActiveConfiguration
        Set swRootComp = swConf.GetRootComponent
        'Traverse assembly
        TraverseComponent swRootComp
        
 
        Else
        MsgBox ("File is not assembly")
        End 'Exit if file is not assembly
            'Code for parts and drawings to be added later
            

    End If
End If

End Sub

Sub TraverseComponent(swComp As SldWorks.Component2)
    'this recursively traverses all of the components in an assembly
    Dim vChildComp                  As Variant
    Dim swChildComp                 As SldWorks.Component2
    Dim ModName                     As String
    

    vChildComp = swComp.GetChildren

    For i = 0 To UBound(vChildComp)
        Set swChildComp = vChildComp(i)
        ModName = swChildComp.Name

        Set Part = swChildComp.GetModelDoc()
        Call StartForm

    Next i
End Sub

Sub StartForm()

Load frmCustomProperties()
frmCustomProperties.Show
frmCustomProperties.txtTitle.SetFocus

End Sub

The problem now is how to transmit "Part" trough StartForm() to Form_Load() in form code. I declared "Public Part as Object" but the Form_Load() still doesn't see it.

RE: API, Assembly traversal, grab children attribute

Fixed the "Part" problem. Assembly has to be loaded in memory (not lightweight) for the components to be "seen".
The question now is: In TraverseComponent I want to pass control to a form and stop execution until form is updated and processed. Then return to TraverseComponent for next component. What happens now is the form is loaded and shown then without waiting or input, the execution returns to TraverseComponent and  continues the loop until the end.
How do I keep the control to the form, until I hit an "Ok" button or so.

RE: API, Assembly traversal, grab children attribute

frmCustomProperties.Show
frmCustomProperties.txtTitle.SetFocus
While frmCustomProperties.Visible
     DoEvents
Wend

Of course, the final line of the "OK" button's OnClick event would be Me.Hide, which hides the form, turning its "Visible" property to "False".

Alternately, in the properties of the form itself you can specify its Modality.  I believe you can make it either Application Modal, which freezes all SW functionality while it's visible, or System Modal, which freezes your system until it's hidden.

RE: API, Assembly traversal, grab children attribute

handleman, thank you for being out there.

From MSDN Library:

Quote:

If a form is displayed as modal, the code following the Show method is not executed until the dialog box is closed. However, when a form is shown as modeless, the code following the Show method is executed immediately after the form is displayed.

So you are right and you deserve another star.

RE: API, Assembly traversal, grab children attribute

Thanks handleman, a star for you.

Bradley

RE: API, Assembly traversal, grab children attribute

This is really weird.

CODE

    bExclude = swChildComp.ExcludeFromBOM 'evaluates to True
    If (Not bExclude) Then Call StartForm

My expectation was that when the boolean bExclude returns True, the Call StartForm will not be executed. But it is!!!

If I modify the code like this to explicitly set bExclude value,

CODE

    bExclude = swChildComp.ExcludeFromBOM 'evaluates to True
    bExclude = True
    If (Not bExclude) Then Call StartForm

the Call StartForm is skipped, as expected

RE: API, Assembly traversal, grab children attribute

After closing and opening VB and changing the declaration of bExclude from "Dim bExclude As Boolean" to "Dim bExclude" everything is fine.

Obviously there's another hurdle. My "Part" in the code above is a ModelDoc2 type (or so I think). So
ModelDoc2.DeleteCustomInfo2..
ModelDoc2.AddCustomInfo3..
ModelDoc2.CustomInfo2...

should work. The last one does, the first one doesn't. I don't get an error, it's just doesn't delete the properties. It's not a "case" issue.

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Eng-Tips Forums free from inappropriate posts.
The Eng-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Eng-Tips forums is a member-only feature.

Click Here to join Eng-Tips and talk with other members!


Resources