Add component attribute find number

The following journal is an extension of the code presented in the processing components tutorial.

This journal will recursively walk through the assembly structure and prompt for a "find number" to be added to each component as an attribute. Subsequent runs of the journal will ignore components that already have a unique find number attribute.

The journal does limited error checking, and due to the order of processing of subsequent runs, it may prompt for a find number for a component that already has one. In short, the code needs some improvements before it is put into a 'production environment'.

The code is offered 'as-is', the user is responsible for testing and any necessary edits for their environment.

'Journal to recursively walk through the assembly structure
' will run on assemblies or piece parts
' will step through all components of the displayed part
' and prompt for/add a "callout" attribute to each component
'NX 7.5, native
'February 29, 2012
 
'edit April 9, 2013: error handling more robust
'    instead of using the generic ApplicationException, use NXException with associated error code
'    to check for "attribute not found" error (NX error code: 512008)
 
Option Strict Off
 
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies
 
Module NXJournal
 
    Public theSession As Session = Session.GetSession()
    Public ufs As UFSession = UFSession.GetUFSession()
    Public lw As ListingWindow = theSession.ListingWindow
    Dim componentList As New Dictionary(Of String, String)
    Dim blnCancel As Boolean = False
 
    '***** change the value of the following constant to your desired attribute title
    Const attributeTitle As String = "MYCALLOUT"
    '*******************************************
 
    Sub Main()
        Dim workPart As Part = theSession.Parts.Work
        Dim dispPart As Part = theSession.Parts.Display
        Dim blnGatheringInfo As Boolean = True
        Dim i As Integer
 
        Dim markId1 As Session.UndoMarkId
        markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Start")
 
        lw.Open()
        For i = 0 To 1
            Try
                Dim c As ComponentAssembly = dispPart.ComponentAssembly
                If Not IsNothing(c.RootComponent) Then
                    reportComponentChildren(c.RootComponent)
                End If
            Catch e As Exception
                theSession.ListingWindow.WriteLine("Failed: " & e.ToString)
            End Try
            blnGatheringInfo = False
        Next
        'lw.WriteLine("Done processing")
        lw.Close()
 
        theSession.SetUndoMarkName(markId1, "Add callout attributes")
        theSession.SetUndoMarkVisibility(markId1, Nothing, Session.MarkVisibility.Visible)
 
    End Sub
    '**********************************************************
    Sub reportComponentChildren(ByVal comp As Component)
 
        For Each child As Component In comp.GetChildren()
            '*** insert code to process component or subassembly
            If blnCancel Then
                Exit Sub
            Else
                processComponent(child)
                reportComponentChildren(child)
            End If
        Next
    End Sub
    '**********************************************************
    Sub processComponent(ByRef myComp As Component)
        Dim previousValue As String = ""
        Dim currentValue As String = ""
 
        If blnCancel Then
            Exit Sub
        End If
 
        If componentList.ContainsKey(myComp.DisplayName) Then
            'component is in list
            previousValue = componentList.Item(myComp.DisplayName)
            'add code to validate attribute value here
            Try
                'is the attribute set on this component, and does it match the value in the list?
                currentValue = myComp.GetStringAttribute(attributeTitle)
                If currentValue <> previousValue Then
                    myComp.SetAttribute(attributeTitle, previousValue)
                End If
            Catch ex As NXException
		'512008 = attribute not found
		If ex.ErrorCode = 512008 Then
                    'component is in list but does not have the attribute, create attribute and set to value in list
                    myComp.SetAttribute(attributeTitle, previousValue)
                Else
                    'some other error occurred
                    lw.WriteLine("## Error: " & ex.ErrorCode & " : " & ex.ToString)
                End If
            End Try
        Else
            'component is not yet in list
            Try
                'it is possible the component has the attribute assigned from a previous run
                'or manual entry, but the component has not been processed yet by this run
                currentValue = myComp.GetStringAttribute(attributeTitle)
                If ValueExists(currentValue) Then
                    'attribute has been assigned, but the value is already in use by a different component
                    AssignAttribute(myComp)
                Else
                    'attribute has been assigned and is unique among components processed so far
                    componentList.Add(myComp.DisplayName, currentValue)
                End If
 
            Catch ex As NXException
		If ex.ErrorCode = 512008 Then
                    'component does not have attribute
                    AssignAttribute(myComp)
                Else
                    'some other error occurred
                    lw.WriteLine("## Error: " & ex.ErrorCode & " : " & ex.ToString)
                End If
            End Try
 
        End If
 
    End Sub
    '**********************************************************
    Function ValueExists(ByVal value As String) As Boolean
 
        For Each key As String In componentList.Keys
            If value = componentList.Item(key) Then
                Return True
                Exit Function
            End If
        Next
        Return False
 
    End Function
    '**********************************************************
    Sub AssignAttribute(ByRef theComponent As Component)
 
        Dim newValue As String = ""
        Dim temp As String = ""
        Dim i As Integer = 1
 
        Do While ValueExists(i.ToString)
            i += 1
        Loop
        Do
            temp = newValue
            newValue = InputBox("Enter value of " & attributeTitle & " for component: " & theComponent.DisplayName, theComponent.DisplayName, i.ToString)
            If newValue = "" Then
                'user pressed cancel
                blnCancel = True
                Exit Sub
            End If
            If ValueExists(newValue) Then
                MsgBox("Value: " & newValue & " is already in use, please enter a new value", MsgBoxStyle.Exclamation + MsgBoxStyle.OkOnly, "Error")
            End If
            'add code to validate entered value
        Loop While ValueExists(newValue)
        componentList.Add(theComponent.DisplayName, newValue)
        theComponent.SetAttribute(attributeTitle, newValue)
 
    End Sub
    '**********************************************************
    Public Function GetUnloadOption(ByVal dummy As String) As Integer
        Return Session.LibraryUnloadOption.Immediately
    End Function
    '**********************************************************
 
End Module

Comments

So I see that when I have an assembly open and execute the script it will add the attribute to the components. With the assembly displayed, when I examine the properties of the components the MYCALLOUT attribute is set with the assigned value. However, when I open the part in a new window I cannot find the attribute. How would I set the attribute so that it is assigned AT THE PART LEVEL and NOT FOR THE PART AT THE ASSEMBLY LEVEL. What I am trying to do is do a bulk assignment of attributes to all the components in a design (ie, Job Number, Designer, Date) that are the same so that when the drawing is created the the appropriate fields are automatically populated with these values.

Rather than adding the attributes to the component, you will want to add them to the part which defines the component geometry. You can get at this part by using the component.Prototype property.

As soon as work lets up and I'm not so busy designing I'll have to take the time to figure this out. Isn't it the way it seems to go, when you're busy you want to try and make things go quicker but don't have enough time to do it.

Thanks for all the examples you've posted. I hope that once I can, I'll have some useful journals to contribute as well.

Hi,

allready if I am having a attribute with the same name it is not updating the existing value. Can you please change the code to change the value of existing attribute.

Stay Hungry
Stay Foolish

How do you get the aal the attributes of the parent File onto a txt file or listing window?
Thanks

Carlo Tony Daristotile

By "parent file" do you mean you have a component and you want to report all the part attributes of the file where the geometry is defined (the prototype part)?

Also, what version of NX are you using? Part attributes changed some starting at NX 8.

by Parent I mean the Master Assembly.
NX 8.0.3.4

Carlo Tony Daristotile

How do I look at these, the attributes seem hidden.

Dan Gaigalas

Right click the component and choose Properties -> Attributes to view them. They are meant to be used in a note or parts list callout.