iPart.FindRow in VBA

iPart.FindRow in VBA

damian_dymczyk
Contributor Contributor
654 Views
6 Replies
Message 1 of 7

iPart.FindRow in VBA

damian_dymczyk
Contributor
Contributor

Hello All, I'm trying to compose a code to create a new member of iPart straight from Assembly. Macro is doing what it should and for each iPart component is adding new row with value taken from user Parameter of assembly. My problem start when I have two iParts from the same iPartFactory, I end up with two iParts with the same value. I know that in iLogic there is a snippet Part.FindRow that would suit perfect to make an If condition, that when it's true row would change to existing else new row would be created. I cannot find similar solution in VBA. Can I count on your help? 

Here is the code

Sub AddNewMember()

 
'originally determin variables
Dim oCompDef As Inventor.ComponentDefinition
Set oCompDef = ThisApplication.ActiveDocument.ComponentDefinition
Dim oCompOcc As ComponentOccurrence
Dim oFerCompDef As ComponentDefinition
Dim oiPart As iPartMember

' Get the active document. This assumes it is a assembly document.
Dim oDoc As Document
Set oDoc = ThisApplication.ActiveDocument

' Get the Parameters collection.
Dim oParams As Parameters
Set oParams = oDoc.ComponentDefinition.Parameters

' Get the Parameter called "Length"
Dim oParam As Parameter
Set oParam = oParams.Item("Test1")

' Get the value of the parameter. This value is in the
' internal units of Inventor. If the parameter defines
' a length unit then the value is always returned in
' centimeters.
Dim dLength As Double
dLength = oParam.Value * 10
Debug.Print dLength
Dim oW As String
oW = CStr(dLength)
Debug.Print oW
For Each oCompOcc In oCompDef.Occurrences
If oCompOcc.IsiPartMember = True Then
    Dim definitionMember As PartComponentDefinition
    Set definitionMember = oCompOcc.Definition
    Dim iPartMember As iPartMember
    Set iPartMember = definitionMember.iPartMember
    Dim factory As iPartFactory
    Set factory = iPartMember.ParentFactory
    Dim doc As PartDocument
    Set doc = factory.Parent
    Dim defintionFactory
    Set definitionFactory = doc.ComponentDefinition
    Debug.Print doc.FullFileName
     ' Open the factory document invisible.
Dim oPartDoc As PartDocument

Set oPartDoc = ThisApplication.Documents.Open(doc.FullFileName, False)
    
    On Error Resume Next

    Dim oFactory As iPartFactory

    Set oFactory = oPartDoc.ComponentDefinition.iPartFactory
    'Get the iPartTable

'    If Err > 0 Or oFactory Is Nothing Then

'    Exit Sub

'    End If

'   Get the part number used in the iPart table

    Dim row As iPartTableRow

    Set row = oFactory.TableRows.Item(oFactory.TableRows.Count)

    Dim sPartNumber As String

    If Not row Is Nothing Then

        sPartNumber = row.MemberName

    End If

    Dim pos As Integer

    pos = InStrRev(sPartNumber, "-")

    Dim str As String

    str = Left(sPartNumber, pos)

    Member = Left(sPartNumber, pos - 1)

    Dim iNumber As Integer

    iNumber = Right(sPartNumber, Len(sPartNumber) - pos)

    'Assume the off of the parameter's value (between two rows) is 0.5cm

    Dim off As Double

    off = 0.5

    Dim oWorkSheet

     Set oWorkSheet = oFactory.ExcelWorkSheet

    Dim oCells

     Set oCells = oWorkSheet.Cells
     
     

    ' New row's value...

    If (iNumber + 1) < 100 Then

        sPartNumber = str + "0" + CStr(iNumber + 1)

    Else

        sPartNumber = str + CStr(iNumber + 1)

    End If

    Dim oCell

     oCell = oCells.Insert(, True)

    oCells.Item(row.Index + 2, 1) = sPartNumber

    oCells.Item(row.Index + 2, 2) = Member

    oCells.Item(row.Index + 2, 3) = oW

   ' oCells.Item(row.Index + 2, 7) = "Include"

    Dim oUM As UnitsOfMeasure

     Set oUM = oPartDoc.UnitsOfMeasure

ThisApplication.CommandManager.ControlDefinitions.Item("DimensionDisplayEqn").Execute

    Dim i As Integer

    Dim oParameter As Parameter

    For i = 4 To 4 + oPartDoc.ComponentDefinition.Parameters.UserParameters.Count

        Set oParameter = FindParameterByName(oPartDoc, oCells.Item(1, i).Formula)

        If oParameter.Name <> oPartDoc.ComponentDefinition.Parameters.UserParameters.Item(4).Name Then

            oCells.Item(row.Index + 2, i) = oUM.GetStringFromValue(oParameter.Value + off * (row.Index), oParameter.Units)

        Else

            oCells.Item(row.Index + 2, i) = oPartDoc.ComponentDefinition.Parameters.UserParameters.Item(4).Expression

        End If

    Next

    Set oUM = Nothing

    Dim oWB

     Set oWB = oWorkSheet.Parent

    oWB.Save

    oWB.Close

    MsgBox ("Add a row - done!")

 

End If
Next


End Sub

 

Function FindParameterByName(oP As PartDocument, Nazwa As String) As Parameter

Dim i As Long

For i = 1 To oP.ComponentDefinition.Parameters.UserParameters.Count

If UCase(oP.ComponentDefinition.Parameters.UserParameters.Item(i).Name) = UCase(Nazwa) Then

    Set FindParameterByName = oP.ComponentDefinition.Parameters.UserParameters.Item(i)

    Exit For

End If

Next

End Function
0 Likes
655 Views
6 Replies
Replies (6)
Message 2 of 7

A.Acheson
Mentor
Mentor

Hi @damian_dymczyk

So it looks like your searching through the factory table which is correct. Where are you having the trouble? Were you able to find the cell value if it exists? 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 3 of 7

damian_dymczyk
Contributor
Contributor

In iLogic I would use z =iPart.FindRow(doc.FullFileName, "ModuleLength", "=", oW, "Position", "=", "Horizontal") but I want to make it in VBA for exercises and I got stuck. I don't know how to find row and make it active when two cells need to be matched.

 

    Dim oCells

     Set oCells = oWorkSheet.Cells
     
    'So here I know that I need to have  if condition that will check two columns
 for values that are equal parameters I declare in the assembly then  true then do nothing

else
code will start adding new row to iPartFactory
    ' New row's value...

 

 

0 Likes
Message 4 of 7

A.Acheson
Mentor
Mentor

There is probably a few ways to go about this but how about a function to check the column and rows for the presence of the value. If none found return -1. You can then compare against another column  and see if the row matches. If you have non unique data in the columns you might need to add the row number to a list of string  for each columns and compare the two lists. I haven't factored that in with the below function. there might even be a better way if you search the issue with excel VBA forums. Here is where I got most of the function layout. 

 

A = GetRowIndex(oFactory, "Part Number", "Enter a cell Value to check")
    MsgBox (A)

 

 

Private Function GetRowIndex(ByVal Factory As iPartFactory, _
                                ByVal ColumnName As String, ByVal RowValue As String) As Long
    ' Iterate through all of the columns looking for a
    ' match to the input name.
    Dim i As Long
    For i = 1 To Factory.TableColumns.Count
        Dim oColumn As iPartTableColumn
        Set oColumn = Factory.TableColumns.Item(i)
        ' Compare this column with the input name.
        If LCase(oColumn.DisplayHeading) = LCase(ColumnName) Then
            ' A matching column was found so check the row value.
           For j = 1 To Factory.TableRows.Count
            Dim oRow As iPartTableRow
            Set oRow = Factory.TableRows.Item(j)
            If RowValue = oRow.Item(j).Value Then
                GetRowIndex = j
                Exit Function
            End If
            Next
        End If
    Next

    ' The row wasn't found so return -1.
    GetRowIndex = -1
End Function

 

 

 

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 5 of 7

damian_dymczyk
Contributor
Contributor

Hi @A.Acheson thanks for the reply I manage to add the function to the code but when I run it the MsgBox(A) display empty box. I'm really suprise that snippet is not available in VBA I even made a small research and find this IiPartRowChanger.FindRow Method

but I don't even know when to start to create this function.

 

Sub x()

 
'originally determin variables
Dim oCompDef As Inventor.ComponentDefinition
Set oCompDef = ThisApplication.ActiveDocument.ComponentDefinition
Dim oCompOcc As ComponentOccurrence
Dim oFerCompDef As ComponentDefinition
Dim oiPart As iPartMember

' Get the active document. This assumes it is a assembly document.
Dim oDoc As Document
Set oDoc = ThisApplication.ActiveDocument

' Get the Parameters collection.
Dim oParams As Parameters
Set oParams = oDoc.ComponentDefinition.Parameters

' Get the Parameter called "Length"
Dim oParam As Parameter
Set oParam = oParams.Item("Test1")

' Get the value of the parameter. This value is in the
' internal units of Inventor. If the parameter defines
' a length unit then the value is always returned in
' centimeters.
Dim dLength As Double
dLength = oParam.Value * 10
Debug.Print dLength
Dim oW As String
oW = CStr(dLength)
Debug.Print oW
For Each oCompOcc In oCompDef.Occurrences
If oCompOcc.IsiPartMember = True Then
    Dim definitionMember As PartComponentDefinition
    Set definitionMember = oCompOcc.Definition
    Dim iPartMember As iPartMember
    Set iPartMember = definitionMember.iPartMember
    Dim Factory As iPartFactory
    Set Factory = iPartMember.ParentFactory
    Dim doc As PartDocument
    Set doc = Factory.Parent
    Dim defintionFactory
    Set definitionFactory = doc.ComponentDefinition
    Debug.Print doc.FullFileName
     ' Open the factory document invisible.
Dim oPartDoc As PartDocument

Set oPartDoc = ThisApplication.Documents.Open(doc.FullFileName, False)
    
    On Error Resume Next

    Dim oFactory As iPartFactory

    Set oFactory = oPartDoc.ComponentDefinition.iPartFactory
    'Get the iPartTable

'    If Err > 0 Or oFactory Is Nothing Then

'    Exit Sub

'    End If

'   Get the part number used in the iPart table

    Dim row As iPartTableRow

    Set row = oFactory.TableRows.Item(oFactory.TableRows.Count)

    Dim sPartNumber As String

    If Not row Is Nothing Then

        sPartNumber = row.MemberName

    End If

    Dim pos As Integer

    pos = InStrRev(sPartNumber, "-")

    Dim str As String

    str = Left(sPartNumber, pos)

    Member = Left(sPartNumber, pos - 1)

    Dim iNumber As Integer

    iNumber = Right(sPartNumber, Len(sPartNumber) - pos)

    'Assume the off of the parameter's value (between two rows) is 0.5cm

    Dim off As Double

    off = 0.5

    Dim oWorkSheet

     Set oWorkSheet = oFactory.ExcelWorkSheet

    Dim oCells

     Set oCells = oWorkSheet.Cells
     
     A = GetRowIndex(oFactory, "ModuleLength", oW)
    MsgBox (A)

    ' New row's value...

    If (iNumber + 1) < 100 Then

        sPartNumber = str + "0" + CStr(iNumber + 1)

    Else

        sPartNumber = str + CStr(iNumber + 1)

    End If

    Dim oCell

     oCell = oCells.Insert(, True)

    oCells.Item(row.Index + 2, 1) = sPartNumber

    oCells.Item(row.Index + 2, 2) = Member

    oCells.Item(row.Index + 2, 3) = oW

   ' oCells.Item(row.Index + 2, 7) = "Include"

    Dim oUM As UnitsOfMeasure

     Set oUM = oPartDoc.UnitsOfMeasure

ThisApplication.CommandManager.ControlDefinitions.Item("DimensionDisplayEqn").Execute

    Dim i As Integer

    Dim oParameter As Parameter

    For i = 4 To 4 + oPartDoc.ComponentDefinition.Parameters.UserParameters.Count

        Set oParameter = FindParameterByName(oPartDoc, oCells.Item(1, i).Formula)

        If oParameter.Name <> oPartDoc.ComponentDefinition.Parameters.UserParameters.Item(4).Name Then

            oCells.Item(row.Index + 2, i) = oUM.GetStringFromValue(oParameter.Value + off * (row.Index), oParameter.Units)

        Else

            oCells.Item(row.Index + 2, i) = oPartDoc.ComponentDefinition.Parameters.UserParameters.Item(4).Expression

        End If

    Next

    Set oUM = Nothing

    Dim oWB

     Set oWB = oWorkSheet.Parent

    oWB.Save

    oWB.Close

    MsgBox ("Add a row - done!")

 

End If
Next


End Sub

Function FindParameterByName(oP As PartDocument, Nazwa As String) As Parameter

Dim i As Long

For i = 1 To oP.ComponentDefinition.Parameters.UserParameters.Count

If UCase(oP.ComponentDefinition.Parameters.UserParameters.Item(i).Name) = UCase(Nazwa) Then

    Set FindParameterByName = oP.ComponentDefinition.Parameters.UserParameters.Item(i)

    Exit For

End If

Next

End Function 

Private Function GetRowIndex(ByVal Factory As iPartFactory, _
                                ByVal ColumnName As String, ByVal RowValue As String) As Long
    ' Iterate through all of the columns looking for a
    ' match to the input name.
    Dim i As Long
    For i = 1 To Factory.TableColumns.Count
        Dim oColumn As iPartTableColumn
        Set oColumn = Factory.TableColumns.Item(i)
        ' Compare this column with the input name.
        If LCase(oColumn.DisplayHeading) = LCase(ColumnName) Then
            ' A matching column was found so check the row value.
           For j = 1 To Factory.TableRows.Count
            Dim oRow As iPartTableRow
            Set oRow = Factory.TableRows.Item(j)
            If RowValue = oRow.Item(j).Value Then
                GetRowIndex = j
                Exit Function
            End If
            Next
        End If
    Next

    ' The row wasn't found so return -1.
    GetRowIndex = -1
End Function

 

 

0 Likes
Message 6 of 7

A.Acheson
Mentor
Mentor

Maybe ensure the variable is declared as long. I ran the code exactly as you have it and it returns -1 for non existing parameter.

 

Yes I am not sure about using IiPartRowChanger.FindRow Method in VBA.

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 7 of 7

damian_dymczyk
Contributor
Contributor

Hello All, after a bit of research I came to the conclusion that it is waaaay more convenient to do with iLogic. I refer to this forum post where my struggle is solved in 3 lines of code:

https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/iparts-and-member-part-naming-using-...

 

Thank you @A.Acheson for your input!

0 Likes