Creating a Tracker Checkboxes tool using Python

I haven’t found a post on how to create a Tracker node checkboxes tool or how to work with the tracks knob in the Tracker node using Python, so I thought I’d write something about it.

This post assumes the reader has some understanding of Nuke and a little understanding of Python. It is also meant to help, or formally introduce, some fundamental Python concepts to those who are only a little familiar and want to have a better understanding.

For those who want to continue learning Python, I highly recommend reading and going through Automate The Boring Stuff With Python, a free book.

You may download and use this tool by clicking on the Nukepedia link at the end of this post. I would also love to read your comments, suggestions, or feedback, if you have any. Thanks!

— Jazlyn


1. Creating a tab in the Tracker node:

The code above defines a function that creates a tab in the Tracker node. The tab contains:

  • one string knob

  • three boolean knobs

  • one button

The button executes a block of code that will check either all or x amount of T, R, or S boxes in the Tracker node.


The code begins with:

import nuke

This line tells the computer to import the “nuke” MODULE so that we can use its code. We have to import the nuke module to use methods, such as . . .

nuke.thisNode()

Module

A module is a file that contains Python code. Import statements bring in modules into our main program so we can use that Python code in our code.


def tracker_checkboxes_tab():

In the line above, I define a FUNCTION. This will create the tab in the Tracker node.

Function

A function contains a block of code designed to do one specific job. When we want to perform that task, we define a function, and then call on that function. We may name a function whatever we’d like, but according to Pep8 (on function and variable names), or the official Python style guide, the function name should be lowercase and contain underscores instead of spaces (YouTube tutorial on functions).


"""This function creates a tab in the Tracker node that lets the artist select the amount of T, R, S Tracker checkboxes they want to check."""

The DOCSTRING above tells us what the function does.

docString

Doctrings are comments that describe what a function does. They are similar to COMMENTS, which I define below, in that Python skips over them. They are only there for other programmers to know what your function does.

# Define Variables:

Comment

Comments like "# Define Variables:” either let other programmers know what is happening in your code or remind you of what your code is doing. Comments start with a hashtag (#) and Python skips over them.


tab = nuke.Tab_Knob('Check Boxes')

In the code above, I define a VARIABLE that contains a value to create the knob that I want to appear in the Tracker node. In other words, the following variable . . .

tab =

. . . stores the following value . . .

nuke.Tab_Knob('Check Boxes') 

. . . which creates a tab in the Tracker node.

Variable

Think of a variable as a box in the computer’s memory that can store a value (YouTube tutorial on variables).


Next, in the code below, I create a knob which an artist can type a string value into . . .

number_of_trackers = nuke.String_Knob(
'number_of_trackers',
'number of trackers:',
'All'
)

In the code below, I name variables which store values that create boolean knobs (or checkboxes) . . .

  • t_boolean_knob = (see GitHub code)
  • r_boolean_knob = (see GitHub code)
  • s_boolean_knob = (see GitHub code)

Boolean Values

Boolean values are True or False values (named after mathematician George Boole). In our tool, True will check the checkbox, and False will uncheck the checkbox.


Lastly, the code below creates a variable that stores a value that creates a button which will execute the code . . .

pyknob = nuke.PyScript_Knob(
'check_tracker_boxes', 
'execute', 
'tracker_checkboxes()' 
)

pyknob.setFlag(nuke.STARTLINE)
node.addKnob(pyknob)

“STARTLINE” puts the pyknob button on a separate line than the other knobs.

nuke.addOnCreate( 
lambda: tracker_checkboxes_tab(), 
nodeClass='Tracker4'

)

“addOnCreate" adds the tab knob, and the rest of the knobs, to all of the Tracker nodes in Nuke.


2. Defining our main function and getting the number of tracks from the toScript():

The code above defines a function that contains the block of code that will check all or x amount of T, R, or S checkboxes in the Tracker node; defines variables that I will use in my code; and generates the number of tracks in the Tracker node by the toScript() method.


In the code below, I define our main function and label what the function does:

def tracker_checkboxes(): 
    """This function checks all or x amount of T, R, and S checkboxes in the Tracker node.""

In the code that follows, I define all of the variables I will use. Personally, I like to start off by defining all of my necessary variables upfront, as I find it makes it easier to refer to them later on.

# Variables: 
this_node = nuke.thisNode() 
knob = this_node['tracks'] 
num_columns = 31 
col_translate = 6 
col_rotate = 7 
col_scale = 8 
count = 0 
trackers_knob_value = this_node.knob('number_of_trackers').value() 
t_knob_value = this_node.knob('translate_box').value() 
r_knob_value = this_node.knob('rotate_box').value() 
s_knob_value = this_node.knob('scale_box').value()

# Put toScript in list:
trackers = []
script = this_node['tracks'].toScript()
trackers.append(script) # add to list

# Get number of tracks from list: 
for item in trackers: 
    total_tracks = item.count('\"track ')

In the code above, I put the information generated from the toScript() into the trackers list, and then I use a for loop to put the number of tracks into the variable total_tracks.


For Loop

for item in trackers: 
    total_tracks = item.count(
'\"track '

)

A for loop will loop through a block of code x amount of times (YouTube tutorial on for loops).

 

List

trackers = []

A list is a value that contains multiple values in an ordered sequence. Lists are written with square brackets []. and the values in a list (which are called items) are separated by commas (YouTube tutorial on lists).


Explaining the toScript() method:

Say an artist has four tracks in their Tracker node, and they want all four tracks with all T, R, and S boxes to be checked:

We could create a tool that has the artist type in how many tracks they have in their Tracker node, but that wouldn’t be the most user friendly way of doing it. Ideally, we’d like the computer to be able to tell how many tracks there are in the Tracker node.

I’ve yet to find a better way of generating how many tracks there are in the Tracker node (so please comment if you know another way). The way I’ve come up with is to take the number of tracks from the toScript().

If you go into your script editor and type in:

You will discover that the tracks knob in the Tracker node is a Table_Knob. Unfortunately, there is no information about the Table_Knob in the Nuke API. So, in order to figure out how to pull the number of tracks in the Tracker node, we have to explore its methods using print dir(selectednode[‘tracks’].

I’ve been through all of the methods in this list and haven’t found one that tells me how many tracks there are in the Tracker node. The toScript() is the only thing that comes close. If we can use another method, it is preferred, since accessing the toScript() is not the best way to do it. But, so far, it is the only way I’ve found works.

If you print the toScript() and look near the bottom, the toScript() tells you that there are four tracks in the selected Tracker node (“track 1”, “track 2”, “track 3”, “track 4”).

In order to isolate the tracks from the toScript(), I start off by putting all of the information generated from the toScript into an empty list:

# Put toScript in list:
 trackers = []
 script = this_node['tracks'].toScript()
 trackers.append(script) # add to list

Next, I use a for loop to count the parts of the list that say ‘\ “track

 # Get number of tracks from list: 
for item in trackers: 
    total_tracks = item.count('\"track ')

This gives me a number that I store in the variable total_tracks. In this case, total_tracks stores the value 4, as shown below:


3. Check all T, R, and S boxes in all of the tracks in the Tracker node:

In the code above, I use a while loop to check all of the T, R, and S boxes in all of the tracks in the Tracker node.


In the code below, I start by putting what will follow in a try-except block to anticipate a possible error that this code might encounter:

try:

The code above represents the TRY block. I will talk more about the EXCEPT block in the next section.

Try

The “try:” is the beginning of a try-except block, which handles errors or exceptions. If Python encounters an error, your entire program will crash; you want Python to be able to handle these errors, so your code will continue running (YouTube tutorial on error handling).


if trackers_knob_value == 'All':

In the line above, I ask Python to execute the block of code that follows if trackers_knob_value is equal to the value ‘All’. And the ‘All’ value tells the computer to check all of the boxes. In this case, we only want the block of code to execute if trackers_knob_value is set to ‘All’.

if and elif

if and elif statements are kinds of flow control statements (elif is short for “else if”). They are used if you want to execute a block of code only if a certain condition in satisfied (YouTube tutorial on if, elif, and else statements).


while count <= int(total_tracks)-1:

In the code above, I use a WHILE LOOP to loop through the code by the number of tracks there are in the Tracker node; the while loop will only loop through the block of code by the number of tracks there are in the Tracker node.

We generated the number of tracks in the Tracker node earlier by the toScript() method. See the toScript() method section above.

While Loop

A while loop will loop through the block of code as long as, or while, a certain condition is true (YouTube tutorial on while loops).


if all([t_knob_value, r_knob_value, s_knob_value]): 
    knob.setValue(True, num_columns * count + col_translate) 

If t_knob_value is True, I tell the computer to set the value of the Translate checkboxes to knob.setValue(True, num_columns * count + col_translate). The t_knob_value statement will run if and only if t_knob_value is True.


The math we use to set the value of the Translate checkboxes is shown below:

# Math = (True (1) or False (0), 31 columns * track number (0 to infinity) + Translate (6), Rotate (7), or Scale (8))

Or, for the translate boxes, knob.setValue(True, 31 * 0 + 6).

I use the information in the math comment to check the rest of the T, R, and S boxes in the Tracker node. And the elif statements execute code that uncheck the boxes if T, R, or S is False (or if the artist does not want them checked).


The math explained

There are 31 columns in the tracks knob in the Tracker node and each column has a number. The T column is 6, the R is 7, and the S is 8.

If you want to set the first track on the T column, for instance, you will need to set the value to (True, 31 * 0 + 6), which says 31 columns times the track number plus the T column. And if you want to uncheck the boxes, you must replace True with False.

**My code says knob.setValue(True, num_columns * count + col_translate) because in section (2) I assigned num_columns the value of 31 and col_translate the value of 6. And I put count in a the while loop.


4. Check x number of the T, R, and S boxes in x number of the tracks in the Tracker node:

The code above uses a for loop to clear the checkboxes and a while loop to check x amount of T, R, and S boxes in x amount of the tracks in the Tracker node.


I wanted to create an option where the artist can type in the number of tracks they want checked in the Tracker node. So, in the code below, I tell the computer that if trackers_knob_value is not the value ‘All’ (the exclamation point means “not”, so != means not equal), then execute the block of code that follows. The for loop unchecks the boxes, so that the while loop that follows will check the boxes the artist puts in the input knob.

if trackers_knob_value != 'All':
    for track in range(0, int(total_tracks)): 
        knob.setValue(False, num_columns * track + col_translate)
        knob.setValue(False, num_columns * track + col_rotate) 
        knob.setValue(False, num_columns * track + col_scale)

except ValueError: 
    nuke.message('The value you entered was not a number.' 
    ' Please enter a number value or "All".')

Lastly, the except block above handles a possible error this code might encounter. So, if an artist enters a value that is something other than “All” or a number, a message will pop up letting the artist know that they have entered a value that this program does not accept, and they need to either enter a number or “All’.


We did it! If you have any questions, comments, suggestions, recommendations, or if you just want to say hi, please leave a comment below. I hope this post was helpful and informative. Thanks for reading!


Please Download this tool on Nukepedia

or submit a pull request on Github!