HoudiniPython: Making Forms with Qt
Updated: Apr 11, 2021
Combining Houdini with Python is pretty powerful.
Combine it with Qt and you become a god.
What is Qt?
Qt is a Python library useful for generating almost any GUI imaginable.
There's a ton of widgets you can add to the form to make it a lazy artists wet dream.
With Python, you can bind functions to events that are triggered when a person clicks on a button, changes a slider or any other action. Combine it with Houdini and you can place down nodes with the click of a button.
There are two main ways of creating a Qt GUI, the first is by procedurally laying out each element/widget via code. The second is by using Qt Designer, a tool super useful for smashing out a quick ui. We'll be using Qt Designer today, so feel free to give it a download.
Now lets look at two examples of sorcery I've made:
This is a simple dialogue for snapping nodes to a grid of your choosing.
Here's a fun little tool that turns SOPs into the shape they represent (bit meta).
It turns the line into a line and the circle into a circle. You can modify the shape with the slider. Notably, it's also able to read what node/s you have selected and multi-edit.
These programs are stupidly simple, however you can create complex GUIs just by adding more widgets and code.
Now that you have Qt Designer installed, let's get this
Show on the Road.
To start off simple, we'll make a form to place a node.
In Qt Designer, go [File] -> [New] -> [Widget].
Let's lay down a Label, a Push Button, and a Horizontal Line. Feel free to dive into the properties and edit the font/size.
See if you can end up with something as shockingly designed as this:
Select the button and head to the Property Editor.
Under QObject objectName, you will need to set that to something descriptive that you'll be using in your code.
I've called it makeNodeButton.
Now, save this form in a permanent location on your disk where you know the folder path won't change, e.g. C:\Qt\forms\my_first_form\main.ui
Yep it is indeed
Fire up Houdini and lets get down to business.
Feel free to create a [New Shelf..] and store it in a nice place.
On the new shelf, create a [New Tool..].
In the Options tab, let's give it a nice name and label.
Head to the Scripts tab.
Now this is where the Python fun begins.
Start by importing the necessary modules.
import hou from PySide2 import QtCore, QtUiTools, QtWidgets
Add another line to establish where you saved your ui file.
ui_file = 'C:/Qt/forms/my_first_form/main.ui'
Given we are using a predefined GUI, we need to do a few things.
We create a MyForm class and use the init() function (that runs as soon as its created).
We do some fancy stuff with setting up the window, and then we can use self.setWindowTitle() to create a title on the window.
Finally, we construct a new MyForm() and run it's show() function to make it appear.
class MyForm (QtWidgets.QWidget): def __init__(self): super(MyForm, self).__init__() self.ui = QtUiTools.QUiLoader().load(ui_file, parentWidget=self) self.setParent(hou.ui.mainQtWindow(), QtCore.Qt.Window) self.setWindowTitle('Lets Make Nodes') win = MyForm() win.show()
Hit apply, click on the tool in the shelf and hey presto!
Ok so the forms appearing but clicking on the button does nothing.
Time for more Python magic!
Let's make a make_node() function that spawns a node.
ui_file = 'C:/Qt/forms/my_first_form/main.ui' ... def make_node(): hou.node('/obj').createNode('null', "cool_node") ... class MyForm (QtWidgets.QWidget):
We need to run this function when the button is clicked.
To bind Qt Widgets to functions, we use the function connect()
In our init function, we will bind our make_node() function to our makeNodeButton's clicked signal.
Make sure it is spelled the same way as it appears under the objectName in Qt Designer.
self.setWindowTitle('Lets Make Nodes') ... self.ui.makeNodeButton.clicked.connect(make_node) ... win = MyForm() win.show()
Now when you click the button you should spawn a new node on top.
Side Challenge A: Spawn the node in random position
Side Challenge B: Make separate buttons on the form that spawn in different types of nodes.
The cool thing is that each widget has its own set of signals that you can bind functions to.
In an earlier example with the slider, I was binding a function to the QSlider's valueChanged() function. That way when I change the slider, I can get Houdini to react at real-time.
To find what these signals are, I use the Qt Documentation.
You can also bind Houdini signals to functions too, that way doing something in Houdini will run a function.
The syntax is a bit different.
Here's an example:
def selection_changed(node, event_type, **kwargs): print(hou.selectedNodes()) hou.node("/obj/geo1").addEventCallback((hou.nodeEventType.ChildSelectionChanged,), selection_changed)
In that example, every time the selection is changed within the /obj/geo1 context, it runs the selection_changed() function that prints out all the selected nodes.
Assuming you have a label with the objectName called myNodesSelected in your Qt form, you can then run a line in your selection_changed() like..
for thisSelectedNode in selectedNodes: selectedString += thisSelectedNode.name() + "\n" self.ui.myNodesSelected.setText(selectedString)
.. to display all the nodes selected on your very Qt Form.
And that's the basics of implementing Qt into Houdini.
But don't stop there.
Combine it with your Houdini Python knowledge and the possibilities are endless.
Keep experimenting with different widgets to make more useful and advanced forms.
Some ideas you can try:
- Preset Gallery:
Use the List Widget to create a list of possible presets (e.g. 'Sphere of Cubes' button that spawns in the Sphere, Box, and Copy To Points SOP all linked up). Have a Save button that saves your nodes selected. Serialize preset data into a JSON file.
- Master Control Panel
Make a control panel that lets you control the different settings in your project.
e.g. Dial Widget for how many clones spawn, Vertical Slider for the Y position of our hero object, Radio Button for whether to use low resolution mode for low end machines.
- Publishing Wizard
If you use a publishing environment like Shotgun, you can make a wizard in Qt for publishing node setups/triggering ROPs with Python.
The cool thing about Qt and PySide is that any software you use that has Python support means you can integrate Qt.
e.g. Maya and Nuke.
Where to go from here?
Check out: https://zetcode.com/ebooks/advancedpyqt5/ for more tutorials on Python Qt.