Submitted by oguzhan.aydemir on Tue, 04/12/2016 - 04:40
Forums:
Hello,
I am trying to make a custom command button for nx by using nx journal vb scripts. The algorithm is like this;
1)User will choose the areas.
2)The areas will be divided to a constant.
3)If the result is bigger than an other constant, a string message will come to screen. Else an other string message will come to screen.
The problem is the vb code of this algorithm. And the user interface of this command. Can you help me with these problems?
Thank you.
re: divide areas
I'll need more information before I can offer much help. First and foremost, what do you mean by "areas" and how will the user "choose" them? Is the area a face that the user selects and you want to divide it; or maybe the area is a closed set of planar curves that bounds an area? Something else?
The Area Is A Face Of A Solid Component.
The area is a face of a solid component. And there are more than one this component. So user will have to choose each faces. And the total area value of the faces will be used for step 2 and 3 of algorithm which I wrote in question.
re: select faces, report area
The code below shows one way to select faces and report the total surface area.
'NXJournaling.com
'April 14, 2016
'
'Report the total surface area of the selected faces.
Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Module Module1
Dim theSession As Session = Session.GetSession()
Dim theUfSession As UFSession = UFSession.GetUFSession()
Dim lw As ListingWindow = theSession.ListingWindow
Sub Main()
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If
Dim workPart As Part = theSession.Parts.Work
lw.Open()
Dim userFaces As New List(Of Face)
Const undoMarkName As String = "face surface area"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)
If SelectFaces("Select faces", userFaces) = Selection.Response.Cancel Then
'user pressed cancel, exit journal
Return
End If
lw.WriteLine(userFaces.Count.ToString & " faces selected")
Dim myMeasure As MeasureManager = theSession.Parts.Display.MeasureManager()
Dim massUnits(4) As Unit
massUnits(0) = theSession.Parts.Display.UnitCollection.GetBase("Area")
massUnits(1) = theSession.Parts.Display.UnitCollection.GetBase("Volume")
massUnits(2) = theSession.Parts.Display.UnitCollection.GetBase("Mass")
massUnits(3) = theSession.Parts.Display.UnitCollection.GetBase("Length")
Dim totalArea As Double = 0
Dim mb As MeasureFaces
mb = myMeasure.NewFaceProperties(massUnits(0), massUnits(3), 0.99, userFaces.ToArray)
totalArea = mb.Area
lw.WriteLine("")
lw.WriteLine("total surface area: " & totalArea.ToString & " " & massUnits(0).Abbreviation)
lw.Close()
End Sub
Function SelectFaces(ByVal prompt As String, ByRef selFaces As List(Of Face)) As Selection.Response
Dim theUI As UI = UI.GetUI
Dim title As String = "Select faces"
Dim includeFeatures As Boolean = False
Dim keepHighlighted As Boolean = False
Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
Dim scope As Selection.SelectionScope = Selection.SelectionScope.AnyInAssembly
Dim selectionMask_array(0) As Selection.MaskTriple
Dim selObj() As TaggedObject = Nothing
With selectionMask_array(0)
.Type = UFConstants.UF_solid_type
.SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_ANY_FACE
End With
Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObjects(prompt, _
title, scope, selAction, _
includeFeatures, keepHighlighted, selectionMask_array, _
selObj)
If resp = Selection.Response.Ok Then
For Each obj As TaggedObject In selObj
selFaces.Add(CType(obj, NXOpen.Face))
Next
Return Selection.Response.Ok
Else
Return Selection.Response.Cancel
End If
End Function
Public Function GetUnloadOption(ByVal dummy As String) As Integer
'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
End Module
How to add user input in this menu
Thank you.
How to add user input on this command interface. Because user has to input an integer value and after I'll use these total area and input value to make a calculation.
Regards.
re: user input
Have a look at the articles on input boxes and custom input forms:
http://www.nxjournaling.com/content/user-input-input-boxes
http://www.nxjournaling.com/content/using-winforms-journals
The input box is a bit simplistic, but it would be a good place to start.
I want to embed this input in the selection menu
Thank you, I made a user input. But it is not on this selection menu. The command is asking first an input after going to this face selection menu. And it is working properly. I want to embed this input in this selection menu. It could be better for user and would be better design.
I want to embed this input in the selection menu
Thank you, I made a user input. But it is not on this selection menu. The command is asking first an input after going to this face selection menu. And it is working properly. I want to embed this input in this selection menu. It could be better for user and would be better design.
re: selection menu
If you have a "Block UI styler" license, you can create NX style dialog boxes for your code. The block styler is an additional cost license, it doesn't come with the basic modeling license; you will need to check with your system administrator to see if you currently have access to such a license.
Currently I don't have this license for this
I just checked and I don't have this license. Is there any other way to do it?
Thank you!
re: winforms
If you are working on Windows, you can do a lot by using Winforms (see link in previous post); but it may not be as easy as using the block styler. The article on winforms shows just a simple example, but much more is possible.
Assigning value from an attribute as an input.
Hello, This command is working well. I want to update this command as following.
I am taking input value from user currently. I want to assign this value from an attribute of a one of parametric model's attribute.
May you help?
Thank you!
re: get attribute value
The following code will look for a number type part attribute (on the current work part) named "TEST"; if found, the journal will just report the attribute value. Your code can make use of the value as you see fit.
Many NX objects can have attributes, once you have a reference to the proper object, getting the value is very similar to the code below.
Option Strict Off
Imports System
Imports NXOpen
Module Module2
Sub Main()
Dim theSession As Session = Session.GetSession()
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If
Dim workPart As Part = theSession.Parts.Work
Dim lw As ListingWindow = theSession.ListingWindow
lw.Open()
Const attributeName As String = "TEST"
Dim attributeInfo As NXObject.AttributeInformation
Dim testVal As Double
If workPart.HasUserAttribute(attributeName, NXObject.AttributeType.Real, -1) Then
attributeInfo = workPart.GetUserAttribute(attributeName, NXObject.AttributeType.Real, -1)
testVal = attributeInfo.RealValue
lw.WriteLine("attribute value: " & testVal.ToString)
Else
lw.WriteLine("the work part does not have a number attribute named: " & attributeName)
End If
lw.Close()
End Sub
Public Function GetUnloadOption(ByVal dummy As String) As Integer
'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
End Module
How can I sum more than one attributes which are calld same name
This code works well on one attribute which is user input in this case.
Now I want to assign attributes on different components with the same name which is "TestArea" for example. And I want my input as sum of these "TestArea" names values which are the areas which user was picking before.
In this way, user will not have to select the areas one by one. Area attributes will be the input.
May you help?
Thank you!
re: component attributes
The following article shows how to iterate through the components in an assembly:
http://www.nxjournaling.com/content/creating-subroutine-process-all-comp...
If you combine that code with the code above showing how to get an attribute value, you can find all the components with a given attribute and sum the values. When getting the attribute, query the component rather than the work part.
Am I following the true path?
Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies
Module NxJournaling
Public theSession As Session = Session.GetSession()
Public ufs As UFSession = UFSession.GetUFSession()
Public lw As ListingWindow = theSession.ListingWindow
Sub Main()
'Dim workPart As Part = theSession.Parts.Work
Dim dispPart As Part = theSession.Parts.Display
lw.Open
Const attributeName As String = "TEST"
Dim attributeInfo As NXObject.AttributeInformation
Dim testVal As Double
Try
Dim c As ComponentAssembly = dispPart.ComponentAssembly
'to process the work part rather than the display part,
' comment the previous line and uncomment the following line
'Dim c As ComponentAssembly = workPart.ComponentAssembly
If Not IsNothing(c.RootComponent) Then
'*** insert code to process 'root component' (assembly file)
If c.HasUserAttribute(attributeName, NXObject.AttributeType.Real, -1) Then
attributeInfo = c.GetUserAttribute(attributeName, NXObject.AttributeType.Real, -1)
testVal = attributeInfo.RealValue
lw.WriteLine("attribute value: " & testVal.ToString)
Else
lw.WriteLine("the work part does not have a number attribute named: " & attributeName)
End If
lw.WriteLine("Assembly: " & c.RootComponent.DisplayName)
lw.WriteLine(" + Active Arrangement: " & c.ActiveArrangement.Name)
'*** end of code to process root component
reportComponentChildren(c.RootComponent, 0)
Else
'*** insert code to process piece part
lw.WriteLine("Part has no components")
End If
Catch e As Exception
theSession.ListingWindow.WriteLine("Failed: " & e.ToString)
End Try
lw.Close
End Sub
Sub reportComponentChildren(ByVal comp As Component,
ByVal indent As Integer)
For Each child As Component In comp.GetChildren()
'*** insert code to process component or subassembly
lw.WriteLine(New String(" ", indent * 2) & child.DisplayName())
'*** end of code to process component or subassembly
If child.GetChildren.Length <> 0 Then
'*** this is a subassembly, add code specific to subassemblies
lw.WriteLine(New String(" ", indent * 2) &
"* subassembly with " &
child.GetChildren.Length & " components")
lw.WriteLine(New String(" ", indent * 2) &
" + Active Arrangement: " &
child.OwningPart.ComponentAssembly.ActiveArrangement.Name)
'*** end of code to process subassembly
Else
'this component has no children (it is a leaf node)
'add any code specific to bottom level components
End If
reportComponentChildren(child, indent + 1)
Next
End Sub
Public Function GetUnloadOption(ByVal dummy As String) As Integer
Return Session.LibraryUnloadOption.Immediately
End Function
End Module
re: check component attribute
If the attribute that you want to check is on the component, I would suggest modifying the "Sub reportComponentChildren" subroutine; in the "For each child..." loop, check each child object (which represents the component) for the attribute. If you want to keep a grand total of the values, you may need to make the "total" variable a module level variable or pass in the "total" variable "ByRef" to the reportComponentChildren subroutine so that it can modify the value.
How can I query the component?
Journal executes "the work part does not have a number attribute named:" & attributeName" part. I think it is because I couldn't query. How can I query the component in this case?
The code is below.
Thank You!
Sub reportComponentChildren(ByVal comp As Component,
ByVal indent As Integer)
Dim workPart As Part = theSession.Parts.Work
Const attributeName As String = "Test"
Dim attributeInfo As NXObject.AttributeInformation
Dim testVal As String
For Each child As Component In comp.GetChildren()
'*** insert code to process component or subassembly
If workPart.HasUserAttribute(attributeName, NXObject.AttributeType.Real, -1) Then
attributeInfo = workPart.GetUserAttribute(attributeName, NXObject.AttributeType.Real, -1)
testVal = attributeInfo.RealValue
lw.WriteLine("attribute value: " & testVal.ToString)
Else
lw.WriteLine("the work part does not have a number attribute named: " & attributeName)
End If
lw.WriteLine(New String(" ", indent * 2) & child.DisplayName())
'*** end of code to process component or subassembly
If child.GetChildren.Length <> 0 Then
'*** this is a subassembly, add code specific to subassemblies
lw.WriteLine(New String(" ", indent * 2) &
"* subassembly with " &
child.GetChildren.Length & " components")
lw.WriteLine(New String(" ", indent * 2) &
" + Active Arrangement: " &
child.OwningPart.ComponentAssembly.ActiveArrangement.Name)
'*** end of code to process subassembly
Else
'this component has no children (it is a leaf node)
'add any code specific to bottom level components
End If
reportComponentChildren(child, indent + 1)
Next
End Sub
re: component attribute
You will want to query the component (the "child" object reference), not the work part.
Sub reportComponentChildren(ByVal comp As Component,
ByVal indent As Integer)
Const attributeName As String = "Test"
Dim attributeInfo As NXObject.AttributeInformation
Dim testVal As String
For Each child As Component In comp.GetChildren()
'*** insert code to process component or subassembly
If child.HasUserAttribute(attributeName, NXObject.AttributeType.Real, -1) Then
attributeInfo = child.GetUserAttribute(attributeName, NXObject.AttributeType.Real, -1)
testVal = attributeInfo.RealValue
lw.WriteLine("attribute value: " & testVal.ToString)
Else
lw.WriteLine("the work part does not have a number attribute named: " & attributeName)
End If
lw.WriteLine(New String(" ", indent * 2) & child.DisplayName())
'*** end of code to process component or subassembly
If child.GetChildren.Length <> 0 Then
'*** this is a subassembly, add code specific to subassemblies
lw.WriteLine(New String(" ", indent * 2) &
"* subassembly with " &
child.GetChildren.Length & " components")
lw.WriteLine(New String(" ", indent * 2) &
" + Active Arrangement: " &
child.OwningPart.ComponentAssembly.ActiveArrangement.Name)
'*** end of code to process subassembly
Else
'this component has no children (it is a leaf node)
'add any code specific to bottom level components
End If
reportComponentChildren(child, indent + 1)
Next
End Sub
Can't take the second attribute value
Hello first attribute in code works well. I stored it in TestValue1Total variable in the end.But this code writes TestValue1Total value 3 times in screen. What might be the problem here?
And second problem is that I see that second attributes value is 0 despite it is an other nonzero integer value.And it writes the 0 on screen 3 time also.
(Justforinformation: I have 3 subassemblies and 1 component in main assembly. Three of my attributes which has value TestValue1 were defined in each subassemblies components. TestValue2 was defined in this 1 component)
Sub reportComponentChildren(ByVal comp As Component, ByVal indent As Integer)
'First Attributes variables
Const attributeName As String = "Test1"
Dim attributeInfo As NXObject.AttributeInformation
Dim TestValue1 As String
Dim TestValue1Total As Integer = 0
'Second Attributes variables
Const attributeName1 As String = "Test2"
Dim attributeInfo1 As NXObject.AttributeInformation
Dim TestValue2 As Integer
For Each child As Component In comp.GetChildren()
'***insert code to process component or subassembly
If child.HasUserAttribute(attributeName, NXObject.AttributeType.Real, -1) Then
attributeInfo = child.GetUserAttribute(attributeName, NXObject.AttributeType.Real, -1)
TestValue1 = attributeInfo.RealValue
ElseIf child.HasUserAttribute(attributeName1, NXObject.AttributeType.Real, -1) Then
attributeInfo1 = child.GetUserAttribute(attributeName1, NXObject.AttributeType.Real, -1)
TestValue2 = attributeInfo1.RealValue
End If
reportComponentChildren(child, indent + 1)
TestValue1Total = TestValue1Total + TestValue1
Next
If TestValue1Total = 0 Then
Else
lw.WriteLine(TestValue1Total)
End If
End Sub
Thank You!
re: attribute of components
The subroutine is recursive; this means that it calls itself. It will call itself each time a component is found to check if the found component has any children components. A copy of the variables defined in the subroutine will be created on each call. This will have some implications if you want to keep a running total. It may be easiest to declare the total variable outside of the subroutine and update it on each call.
How can I take value from second attribute?
This problem was solved about taking value from first attribute. Now is the problem is that when I write an elseif statement for other attribute. It doesn't work. I can't take value from second attribute. How can I take value from the second attribute as well?
Thanks!
re: second attribute
To get the values of both attributes, use two separate IF statements.
If child.HasUserAttribute(attribute1...
'get value
End if
If child.HasUserAttribute(attribute2...
'get value
End if
When using the If/ElseIf construct; when the If condition returns True, the statements following the If get executed, then control jumps to the End if. None of the ElseIf statments are tested when the If test returns True.
If test1 then
'first statements
ElseIf test2 then
'second statements
ElseIf test3 then
'third statements
Else
'do this when all of the above return False
End If
So, when test1 returns True, "first statements" gets executed, then control jumps down to "End if". If test1 returns False, test2 is evaluated. When test2 returns True, the "second statements" get executed and control jumps down do the "End if". If none of the tests return True, then the statements in the "Else" section get executed.
Thank you!
Thank You! If elseif worked for me.