Nuke Timeout – EP05 – Knob Changed

When we double click on a node, we can see it’s attributes in the properties pane (or in a floating window). These are also called knobs and there are many different types of it. Floating Point Knobs, 2D or 3D Position Knobs, Pulldown Knobs, Checkbox Knobs and many more.

We can even add our own knobs.

Knobs can be visible or hidden. One of the invisible knobs that every node comes with is called knobChanged.
It is usually an empty knob. You can assign a code or script to it that gets executed every time a specific (or all) knob gets changed – hence the name.

You can assign a value (meaning the code) the same way you would do with any other knob by using python.
For example, if I want to change the size slider value of a Blur node, I can use this code (while having the node selected):

sel = nuke.selectedNode()
sel.knob('size').setValue(2)

Knowing this, I can assign a very simple code to the knobChanged knob:

sel = nuke.selectedNode()
sel.knob('knobChanged').setValue('print("Knob has been changed!")')

So every time I change any of the knobs of this node, it will print my string.
In most cases, you only want to do this for one specific knob – with the help of using nuke.thisNode() and nuke.thisKnob() as well as if statements.

def kc_func():
     n = nuke.thisNode()
     k = nuke.thisKnob()
     if k.name() == "size":
          print("The size knob has been changed")

sel = nuke.selectedNode()
sel.knob('knobChanged').setValue('kc_func()')

You have to use quotation marks when you assign the value since the setValue method expects a string and not a function. This way, only the size knob will trigger our code.

Assigning code this way is not really efficient, since you might want to keep it on a global, external level – so you don’t have to type all your script again if you want to assign the same code to other notes. Also, you want to stay in control and independent with your code.
Let’s say you need to tweak the code. Doing it the way we just did, it would not be possible without reassigning everything since we were hard coding it into the knob.
I’ll show you an approach that makes it easier and you will stay more flexible.

Let’s create a new python script in our .nuke directory.

We use the same code as before.

Let’s make sure that we import it as a module in our menu.py. That way it is accessible from within Nuke.

Let’s start a fresh Nuke session.
Now I only need to assign that module and the containing function to my selected node.

sel = nuke.selectedNode()
sel.knob('knobChanged').setValue("kc_script.kc_func()")

Now let’s save the script and close Nuke.
I now go back to my python file and change the string that I would like to print.

If I open up my Nuke script again, the knobChanged value is automatically updated.

Usually you will have to close and reopen Nuke to reflect changes in your python modules, but there is also a way to force an update from within Nuke: Reloading the module.
In Nuke versions below 13 you can use the following function:

#Python2:
reload(kc_script)

Nuke version 13 started using Python 3, so we first have to import the importlib module in order to use the reload feature.

import importlib
importlib.reload(kc_script)

If I now do another change to my python script, I can just use this approach and the knobChanged() knob uses my updated code.

In a lot of cases the knobChanged knob is used to update the control panel appearance.

For example, if I change the value of this pulldown menu, I would make certain attributes available while hiding others.

In the next episode of Timeout, which will focus on efficient retiming in Nuke, I will actually use it to create and delete nodes within a group.