Beginning Journaling using NX Journal

(menu locations in this tutorial are based on NX 7.5, programming language is Visual Basic)

Where to start? The best place to start writing a journal is with the journal recorder. This wonder of modern technology will translate your interactions with NX to journal code, in your language of choice! (this article will use Visual Basic, or VB for short). If you are following along, let’s make sure the journal output language is set to VB before we start.

Setting the Journal Programming Language:
In the menu, choosePreferences -> User Interface...; on the Journaltab choose Visual Basic as the language and make sure the Insert Menu/Dialog Box Commentsoption is checked.

 

Recording the Journal:

For starters, let’s assume you want to change the color of a specified solid body. Start by recording a journal Tools -> Journal -> Record... and specify a file name for your new journal, preferably something that describes its function such as “change_color.vb”. Once the journal recording process starts, you may notice a change in your toolbars and menus. The green marks on the toolbar icons/menu items indicate that journal recording is fully supported by this command; yellow marks indicate the command is partially supported.  

Now that recording is under way, choose Edit -> Object Display... from the menu, pick the solid body of interest, and pick a new display color. OK the changes and then stop the journal recordingTools -> Journal -> Stop recording.

Time to test out the journal. Change the color of the solid body, or perform an Undo to get the original color back; now navigate to Tools -> Journal -> Play... and browse to your new journal file. Select your journal from the list and press the Playbutton. After a short pause, your solid body will change to the color you picked when you recorded the journal.

 

Understanding the New Journal Code:
Open a Windows file explorer window and browse to your new journal file, open it with a text editor (such as notepad) and take a peek at what goes on behind the scenes. Don’t worry if this looks like mumbo jumbo right now, we’ll step through it to see what is going on.  I created a new file and inserted a block feature, then followed the steps outlined above; here is the resulting journal code:

Option Strict Off
Imports System
Imports NXOpen
 
Module NXJournal
Sub Main
 
Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work
 
Dim displayPart As Part = theSession.Parts.Display
 
' ----------------------------------------------
'   Menu: Edit->Object Display...
' ----------------------------------------------
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Start")
 
theSession.SetUndoMarkName(markId1, "Class Selection Dialog")
 
Dim markId2 As Session.UndoMarkId
markId2 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Class Selection")
 
theSession.DeleteUndoMark(markId2, Nothing)
 
theSession.SetUndoMarkName(markId1, "Class Selection")
 
theSession.DeleteUndoMark(markId1, Nothing)
 
' ----------------------------------------------
'   Dialog Begin Edit Object Display
' ----------------------------------------------
' ----------------------------------------------
'   Dialog Begin Color
' ----------------------------------------------
Dim markId3 As Session.UndoMarkId
markId3 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "Edit Object Display")
 
Dim displayModification1 As DisplayModification
displayModification1 = theSession.DisplayManager.NewDisplayModification()
 
displayModification1.ApplyToAllFaces = False
 
displayModification1.ApplyToOwningParts = False
 
displayModification1.NewColor = 103
 
Dim objects1(0) As DisplayableObject
Dim body1 As Body = CType(workPart.Bodies.FindObject("BLOCK(0)"), Body)
 
objects1(0) = body1
displayModification1.Apply(objects1)
 
displayModification1.Dispose()
' ----------------------------------------------
'   Menu: Tools->Journal->Stop Recording
' ----------------------------------------------
 
End Sub
End Module

Option Strict Off means the code will allow some types of implicit conversions, but really it isn’t something we’ll need to worry about right now.

Next up are the Imports statements, which import a specified namespace. It is important to note that these statements do not add more functionality to your code (ie they are not analogous to references to external libraries); rather they allow certain declarations to be abbreviated. In addition to NX code, journals are linked by default to certain .NET libraries. These libraries are:

  • mscorlib.dll
  • System.dll
  • System.Windows.Forms.dll
  • System.Drawing.dll

A Module is declared next with the default name of NXJournal. A module is a container where all the code lives, if you skip down to the end of the journal you will see an End Module statement. Any code you add must be between the Module... End Module statements. You can change the module name to something more descriptive if you like, but since there is only one module in our journal, the default name is just fine. The module also determines the scope of variables and code it contains, but this is a topic for another day.

Sub Main is the block of code that gets called when your journal is run. As your journals get longer and more complex, it is helpful to break the code into multiple subroutines and functions and call them as necessary. Sub Main is where the core logic will reside. Every journal must have a Sub Main.

The next 3 lines initialize the session, display part, and work part for us to reference in our journal. Part and Session are classes in NXOpen, these object variables will give us access to other objects in NX.

All of the code we have looked at so far is included in every recorded journal. If you want to start a journal from scratch, including this code is a good idea.

A comment on comments:
A single apostrophe or the keyword rem indicates the start of a comment, the comment continues to the end of the line. Anything contained in the comment will be ignored by the compiler. Comments serve useful functions:

  • They are most often used to document the code. Use comments to explain tricky bits of code or document the input/output requirements of functions and subroutines. Comments are also often used at the beginning of the code file to explain the who when and what: who wrote the program, when they wrote the program, and what problem the code solves or what process the code automates.
  • Comments are also useful in the debugging process. Use comments to temporarily disable a line or entire block of code to try out an alternative solution without having to delete code that may yet prove useful.

Next up in the code, is the creation of a couple of useless undo marks. As you record and modify journals you will find that the journal recorder often throws in extra bits of code. The undo marks, markId1 and markId2, are good examples of this. The undo marks are created, named, renamed, and finally deleted (set to ‘nothing’) ultimately having no effect on the finished journal. If your journal contains similar code, feel free to delete it.

Creating an undo mark is a good way to start a journal as it will allow any changes made by the journal to be undone if necessary. MarkId3 is the real undo mark here. You can see the string “Edit Object Display” as one of the arguments when the id mark is set. This string is what will appear in the undo list after the journal is run. If the undo function is used, the model will roll back to the state it was in when the undo mark was set in code. It is a good idea to set an undo mark before trying to modify features; if there are any errors during the model update, it can roll back to a known state. Multiple undo marks can be set, which comes in handy in larger multi-step journals; changes can be rolled back in chunks rather than an all or nothing approach.

When declaring variables, this is the normal pattern:

Dim [variable name] as [variable type]

so the line:

Dim displayModification1 As DisplayModification

tells the compiler to set aside a block of memory large enough for a DisplayModification object and the name used to refer to it will be displayModification1. A DisplayModification is a temporary helper NX object that assists in changing the display attributes of one or more objects.

Now that we have a display modification object we can set our preferences:

displayModification1.ApplyToAllFaces = False
displayModification1.ApplyToOwningParts = False
displayModification1.NewColor = 103

As you can see, I picked color 103, cornflower blue, as my new object color. At this point our solid body has not yet changed, in fact the journal doesn’t yet know what object(s) these changes are going to apply to. Which brings us to:

Dim objects1(0) As DisplayableObject
Dim body1 As Body = CType(workPart.Bodies.FindObject("BLOCK(0)"), Body)
objects1(0) = body1

The display modification object requires an array of objects of the type DisplayableObject to work on. The first line creates a 1 element array (arrays are zero based) of DisplayableObjects, line 2 records the solid that I selected (your line of code may be different), and line 3 assigns the body to the array that will be used with the display modification object.

Now that the options are set and the object is specified we can apply our desired changes with

displayModification1.Apply(objects1)

Now that the work is done, we can delete the temporary display modification object and free up the memory it used by calling its Dispose method:

displayModification1.Dispose()

At this point the journal exits and we can see the results in the modeling window. However, should you try to run this journal in a different file you would be met with an error message.

Hand Editing the Journal:
The reason that the journal in its current state will end in a error message when applied to a different file is that your journal is looking for the exact solid that you selected when the journal was recorded. This behavior is referred to as ‘selection stickiness’ and its removal is one of the main reasons for hand-editing journal code. You can greatly increase the usefulness of your code by replacing the hard coded reference to a specific object with a more general selection routine.

Below you will find the same script without the useless undo marks and with the selection stickiness removed.  This journal can now be used on various files to change the selected solid body’s color.

Option Strict Off
 
Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpenUI
 
Module NXJournal
Sub Main
 
Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work
Dim displayPart As Part = theSession.Parts.Display
Dim ufs As UFSession = UFSession.GetUFSession()
 
Dim markId3 As Session.UndoMarkId
markId3 = theSession.SetUndoMark(Session.MarkVisibility.Visible, "Edit Object Display")
 
Dim displayModification1 As DisplayModification
displayModification1 = theSession.DisplayManager.NewDisplayModification()
displayModification1.ApplyToAllFaces = False
displayModification1.ApplyToOwningParts = False
displayModification1.NewColor = 103
 
Dim objects1(0) As DisplayableObject
'Dim body1 As Body = CType(workPart.Bodies.FindObject("BLOCK(0)"), Body)
Dim body1 As Body = SelectSolid()
objects1(0) = body1
displayModification1.Apply(objects1)
displayModification1.Dispose()
 
End Sub
 
Function SelectSolid() As Body
 
    Dim ui As UI = ui.GetUI
    Dim message As String = "Select solid body"
    Dim title As String = "Selection"
 
    Dim scope As Selection.SelectionScope = Selection.SelectionScope.WorkPart
    Dim keepHighlighted As Boolean = False
    Dim includeFeatures As Boolean = True
 
    Dim selectionAction As Selection.SelectionAction = _
       Selection.SelectionAction.ClearAndEnableSpecific
 
    Dim selectionMask_array(0) As Selection.MaskTriple
    With selectionMask_array(0)
       .Type = UFConstants.UF_solid_type
       .Subtype = 0
       .SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_SOLID_BODY
    End With
 
    Dim selectedObject As NXObject = Nothing
    Dim cursor As Point3d
 
    ui.SelectionManager.SelectObject(message, title, scope, _
                                    selectionAction, includeFeatures, _
                                    keepHighlighted, selectionMask_array, _
                                    selectedObject, cursor)
 
    Dim solid As Body = CType(selectedObject, Body)
 
    If solid Is Nothing Then
       Return Nothing
    End If
 
    Return solid
 
End Function
 
End Module

Download the code.

Recap:
In review you can see how we can use NX Journal to create a basic journal designed to change the color of a solid body.  Then we evaluated the code generated by the journal recorder and modified the code to be of broader use with just a few hand coded manipulations. The resulting journal can now change the body color of any part.

Objectives:
We learned how to record a journal. How to interpret the code behind the NX Journal and how to adjust the code to allow a journal to be useful across multiple files.

Comments

I have a rectangle face which is related to the origin of a datum CSYS. I extract one curve from an edge of the face (with no association) and then rotate the CSYS around its axis by 5deg (ofcouse the face is rotated too) and extract curve again....I want to do this for several times. Could you please help me to build an journal file to do this operation?
Thanks in advance (and sorry for my bad English)

Is there a way to add journal to custom/default toolbar or menubar? if so, a article on that will be very helpful.
Also, if you could explain us to convert journals to exe and add it to a toolbar/menubar.

Thanks in advance.

Ashok,
Thanks for the suggestion! I'll make that one of the next articles.

Hello nxjournal,
When would you have the need to compile a journal and what are the advantages of doing so.
Ps great site lots of useful information do you work for Siemens?

JSON

There are several advantages to compiling your code, but I believe they boil down to these three:

  1. Speed
  2. Control
  3. Source code hiding

Strictly speaking, you really cannot run uncompiled code. When you launch an uncompiled journal, it is compiled in the background and loaded into memory then executed and finally it is unloaded from memory by default. Compiled code obviously skips the compilation step and it gives you the option of using other "unload options". In many of the journals on the site you will see a function called "GetUnloadOption"; this is added by the visual studio wizard and I often leave it in the code, but really isn't necessary when running uncompiled code since NX will, by default, unload the code when the journal finishes executing. Compiled code can use the option to stay in memory for the duration of the NX session, eliminating the need to reload the code on subsequent runs.

NX limits the references that can be added to uncompiled journals (as mentioned in the above article). Using compiled code you can add other references at will. You can add a reference to MSOffice to easily work with the Excel or Word object models, for instance.

If you have curious users with no programming experience, they may quickly find that a .vb file is simply a plain text file that they can easily open and change. Compiling to an .exe or .dll file makes it less likely that it will be tampered with by a casual user.

There are other reasons you may want to compile, but I hope this gives you a good overview of the advantages.

p.s. I do not work for Siemens, I am a design engineer with a love of programming and a desire to pass that on to others. Thanks for the compliment on the site, if you have any suggestions please pass them on!

Hi

Do I need any specific licences to be able to compile a VB journal?

Regards
Martyn

You'll need an NX "author" license to sign the compiled code. You can compile the code without the license, but you will get warnings when you (or others) run the code.

One suggestion I have got is the width of the central panel which hold the sample code. Is there a way you could increase the width as I find myself continually having to use the slider to review the complete code. When you are trying to follow it line by line this can a bit of awkward.

JSON

How would you compile the code?

Carlo Tony Daristotile

In the NX help files (programmer's guide section) there is information on compiling and linking NX Open for .NET, this would be a great place to start.

Hello everyone, I am starting my adventure with programming in NX and I need some help.
I am not sure if it is a good place to place my post, but I cannot do it on the forum.

DraftingView[] views = workPart.DraftingViews.ToArray();

foreach (var view in views)
{
UFDraw.ViewLabelParms myLabel = new UFDraw.ViewLabelParms();
myLabel.letter_size_factor = 1.6;
myLabel.letter_format = UFDraw.ViewLabelLetterFormat.ViewLabelDashedLetter;

UFDraw myUfDraw;
Tag viewTag = view.Tag;
myUfDraw.SetViewLabelParms(viewTag, ref myLabel);
}

I want to change the factor for all view labels, but I don't know how to apply this changes to individual views.
I got an error: "Use of unassigned local Variable "myUfDraw.
I have no idea what should be assigned to it.

I would be greatfull for any help.
Thanks. lukaa

Do you have a reference to the UFSession?

The first thing I'd try is:
.SetViewLabelParms(viewTag, myLabel);

It works fine. Thanks.

Hi.
First of all this is very helpfull for journaling beginers. when you added hand written code how we can assure our code code is correct is there any guidelines. Please let me know

Best Regards,
Gani

The only way to make sure the code is correct is to test, test, and test some more. Once your code runs, you now need to test that it is giving correct results for a simple test case. Once that works, test with more complicated or different input. Also, try running your code with invalid or "that's crazy, no one would do that" type input. If the input is valid, your code should give the correct result; if the input is invalid, it should warn the user or at least fail gracefully (without crashing NX or the OS).

So, how do we get to the point that we have code to test? As you work with the API more, you will get familiar with it and get an idea of what is available and what is not. To become more familiar with the API, look at other people's working code. You can find code on this site, at the GTAC solution center, and in various other forums. Don't understand the code or can't find an example of what you need to do? Ask a question in a forum.

An integrated development environment (IDE) such as Microsoft's VB.NET express (free) will also help. It can catch simple errors such as misspelling keywords or passing incorrect arguments to functions. The 'autocomplete' feature will also show you available properties and methods for objects without having to refer back to the help files. Get an IDE, it is a big help.

Links to the GTAC solution center, other forums, and the VB.net IDE can be found on the resources page.

As in the above program of color change, u edit it for general selection by using the code. where should i find codes like this?
please tell me as i have just started to edit the Journals.

The constants and corresponding values for the .Type and .Subtype can be found in:
{NX install folder}\UGOPEN\uf_object_types.h

The constants and corresponding values for the .SolidBodySubtype can be found in:
{NX install folder}\UGOPEN\uf_ui_types.h
scroll down until you find the line:
"/* Constants for selection solid_type */"
In the NX 8.5 version of this file it is line 684.

thank you !!!!!!!!!! can i find the codes similar to this in VB. so that i can use them to edit journals

Let's say you want to filter for point objects; you open uf_object_types.h and find UF_point_type. To use this value in VB, you would use: NXOpen.UF.UFConstants.UF_point_type.

Or, if you have added the line: Imports NXOpen.UF at the top of your journal, you could shorten the above statement to: UFConstants.UF_point_type.

really grateful for the help and guidance!!!!!!!!
thank you very much!!!!!!!!!!!11

will you please upload more examples of hand edititng the journal?????

The following thread on eng-tips.com has an example that you may find helpful:
http://www.eng-tips.com/viewthread.cfm?qid=374824

The link u provided seems to be useful....thank you very much.....

Hi,
I'm working on a journal that switches from one part (lets call it @DB/0001_D/-) to another part with the same number but without the suffix "_D" and vice versa (from "0001" to "0001_D"), if it is loaded in the NX session. So I know what the Part number is, but not the Revision. How can I do that?
Thanks, Eric
NX9.0.3

The strategy will partly depend on the part naming convention and on TC settings. Run the following journal on a part and its corresponding drawing and report the results (in the comments below or email them to me at info@nxjournaling.com).

Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF
 
Module Module25
    Sub Main(ByVal args() As String)
 
        Dim theSession As Session = Session.GetSession()
        Dim lw As ListingWindow = theSession.ListingWindow
 
        lw.Open()
 
        lw.WriteLine("Full Path: " & theSession.Parts.Work.FullPath)
        lw.WriteLine("Leaf: " & theSession.Parts.Work.Leaf)
 
        Try
            Dim partNum As String = theSession.Parts.Work.GetStringAttribute("DB_PART_NO")
            lw.WriteLine("partNum: " & partNum)
 
        Catch ex As NXException
            lw.WriteLine("exception " & ex.ErrorCode.ToString & ": " & ex.Message)
        End Try
 
        lw.Close()
 
    End Sub
 
End Module

Thanks for the reply! The company has the part and the related drawing in separate Teamcenter items, and the drawing is always numbered as PartId + "_D". So I'm trying to make a journal that, when a user has part "0015" set as the displayed part in modeling, looks in the session if there is a drawing "0015_D", set that as the displayed part and switches to Drafting. And vice versa.
Thanks!
Eric

So when you run the journal above, the "partNum" is reported as "0015" and "0015_D", is this correct? or are there other characters prepended/appended on the base number?

I have tested it on the drawing, but it only reports the drawing. The output from the journal above:
Full Path: 009417_D/-
Leaf: 009417_D/-
partNum: 009417_D

Please note that part and drawing are in separate TC items, so the part is added to the drawing as an assembly component:
009417_D (drawing)
- 009417 (part)

I think I will have to go through a list of all open parts/drawings in the session, search for a part "009147" or a drawing "009147_D", and make that one the displayed part. Is this possible?
Thanks, Eric

The following code should get you started.

Option Strict Off
Imports System
Imports NXOpen
 
Module Module1
 
    Dim theSession As Session = Session.GetSession()
 
    Sub Main()
 
        Dim theUI As UI = UI.GetUI
 
        If IsNothing(theSession.Parts.Work) Then
            'active part required
            Return
        End If
 
        Dim workPart As Part = theSession.Parts.Work
        Dim lw As ListingWindow = theSession.ListingWindow
        lw.Open()
 
        Const undoMarkName As String = "NXJ journal"
        Dim markId1 As Session.UndoMarkId
        markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, undoMarkName)
 
        Const prtAttribute As String = "DB_PART_NO"
        Dim currentPart As String
        Dim nextPart As String
        Dim switchToDrafting As Boolean = False
 
        If Not theSession.Parts.Display.HasUserAttribute(prtAttribute, NXObject.AttributeType.String, -1) Then
            lw.WriteLine(prtAttribute & " attribute not found")
            Return
        End If
 
        Try
            'get current display part number
            currentPart = theSession.Parts.Display.GetStringUserAttribute(prtAttribute, -1)
 
        Catch ex As NXException
            theSession.UndoToMark(markId1, undoMarkName)
            lw.WriteLine(ex.Message)
            Return
        Finally
 
        End Try
 
        If currentPart.Substring(currentPart.Length - 1).ToUpper = "D" Then
            'search for corresponding part file
            nextPart = currentPart.Substring(0, currentPart.Length - 2)
            switchToDrafting = False
 
        Else
            'search for corresponding drawing file
            nextPart = currentPart & "_D"
            switchToDrafting = True
 
        End If
 
        Dim found As Boolean = False
        For Each tempPart As Part In theSession.Parts
            Try
                If tempPart.GetStringUserAttribute(prtAttribute, -1) = nextPart Then
                    found = True
                    ChangeDisplayPart(tempPart)
                    If switchToDrafting Then
                        theUI.MenuBarManager.ApplicationSwitchRequest("UG_APP_DRAFTING")
                    Else
                        theUI.MenuBarManager.ApplicationSwitchRequest("UG_APP_MODELING")
 
                    End If
 
                    Exit For
                End If
            Catch ex As NXException
                lw.WriteLine(ex.Message)
            End Try
        Next
 
        If Not found Then
            lw.WriteLine("corresponding part not found in session")
        End If
 
        lw.Close()
 
    End Sub
 
    Sub ChangeDisplayPart(ByVal myPart As Part)
 
        'make the given component the display part
        Dim markId1 As Session.UndoMarkId
        markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Display Part")
 
        Try
            Dim partLoadStatus1 As PartLoadStatus
            Dim status1 As PartCollection.SdpsStatus
            status1 = theSession.Parts.SetDisplay(myPart, False, False, partLoadStatus1)
 
            partLoadStatus1.Dispose()
        Catch ex As NXException
            'optional: add code to log/display error
            theSession.UndoToMark(markId1, "Display Part")
        Finally
            theSession.DeleteUndoMark(markId1, "Display Part")
        End Try
 
    End Sub
 
    Public Function GetUnloadOption(ByVal dummy As String) As Integer
 
        'Unloads the image when the NX session terminates
        GetUnloadOption = NXOpen.Session.LibraryUnloadOption.AtTermination
 
        '----Other unload options-------
        'Unloads the image immediately after execution within NX
        'GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
 
        'Unloads the image explicitly, via an unload dialog
        'GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Explicitly
        '-------------------------------
 
    End Function
 
End Module

I will have to check that tomorrow, as it's late in the evening where I live ;-). The Teamcenter Item ID and the part number in NX are indeed "0015" and "0015_D", so not 0015_D-dwg or something like that. They are revised separately, so the part revision might be 01 and the drawing revision 03. Not sure if that matters. I will let you know tomorrow what the output is.
Thanks a lot!
Eric

Yes, this works! Thanks a lot!

how should i find the parameters in art design and how should i define them. i want to construct such designs and want to make my own dialogue box in NX , so that after selecting the desire art pattern for the solid body , i can give parameters to the design like scale and arrange the design using array. where should i find the codes required for this?