On this page

Overview

The Python Panel Editor window lets you create, edit and delete PySide2 or PyQt5 interfaces that can be displayed in Python Panel panes. The editor also lets you manage the entries in the Python Panel interfaces menu as well as the entries in the Houdini pane tab menu.

Requirements

There are no requirements when building PySide2 interfaces. Houdini ships with PySide2 modules out-of-the-box.

To build interfaces with PyQt5, install the PyQt5 modules on your system. Houdini does its best to find the PyQt5 modules automatically however, if the modules cannot be found then add the installed location to the Python search path.

For example, if PyQt5 is installed at /path/to/site-packages/PyQt5, then set PYTHONPATH=/path/to/site-packages in your environment before starting Houdini. Alternatively, append /path/to/site-packages to the search path through Python code like so:

# Modify search path
import sys
sys.path.append("/path/to/site-packages")

# Now you can import PyQt5
from PyQt5 import QtWidgets

New to Houdini 16.5

Houdini 16.5 no longer automatically scales PySide/PyQt interfaces by Houdini’s Global UI Size preference. The automatic scaling used Qt’s screen scale factor which caused several problems in Houdini’s UI.

In Houdini 16.5 if you desire to use your PySide/PyQt interface with other Houdini UI sizes (i.e. High DPI, or Large, etc.) and have your interface to scale accordingly, then you can do so by calling the new hou.ui.scaledSize() method on hard-coded sizes.

For example, if you had code like this:

button = QtWidgets.QPushButton()
button.resize(200, 30)

Then you can change it to this:

button = QtWidgets.QPushButton()
button.resize(hou.ui.scaledSize(200), hou.ui.scaledSize(30))

You can also call the new hou.ui.globalScaleFactor() function to scale things other than widget sizes. For example:

web_view = QWebEngineWidgets.QWebEngineView()
web_view.setZoomFactor(hou.ui.globalScaleFactor())

New to Houdini 16

Houdini 16 is built with Qt5 so only PySide2 and PyQt5 are supported in Python Panels.

Tip

If you want to continue using PySide or PyQt4 then you must install a Houdini Qt4 build.

Here are a few tips when porting your Python Panel code from PySide to PySide2 and similarly from PyQt4 to PyQt5:

  • Import modules from PySide2 instead of PySide. Similarly, import modules from PyQt5 instead of PyQt4.

  • Additionally import the QtWidgets module because all widget classes have been moved out of QtGui and into QtWidgets.

  • Call .setProperty("houdiniStyle", True) on top-level widget to restore Houdini styling. With PySide2 and PyQt5, Houdini does not automatically apply Houdini styling to custom widget classes.

  • When creating a QMenuBar widget call .setNativeMenuBar(False) to prevent the menu bar from populating the system’s main menu bar on MacOS. The native menu bar default setting changed between Qt4 and Qt5. Alternatively call hou.qt.createMenuBar() to create a QMenuBar widget that works across all platforms.

Tip

hou.qt has a collection of methods for creating common widgets with the Houdini look and feel. The module also has methods for retrieving Houdini icons and colors.

For example, this code in PySide:

from PySide import QtGui

class MyCustomWidget(QtGui.QWidget):
    """A custom widget class that contains a label."""
    def __init__(self):
        QtGui.QWidget.__init__(self)

        label1 = QtGui.QLabel("Hello World")

        layout = QtGui.QVBoxLayout()
        layout.addWidget(label1)
        self.setLayout(layout)

Becomes this code in PySide2:

from PySide2 import QtWidgets

class MyCustomWidget(QtWidgets.QWidget):
    """A custom widget class that contains a label."""
    def __init__(self):
        QtWidgets.QWidget.__init__(self)

        label1 = QtWidgets.QLabel("Hello World")

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(label1)
        self.setLayout(layout)

        # Apply Houdini styling to the main widget.
        self.setProperty("houdiniStyle", True)

Creating and Editing Interfaces

  1. Open the Python Panel Editor from the Windows menu or from the toolbar button in a Python Panel pane tab.

  2. To create a new interface definition, choose the Interfaces tab and click the New Interface button. The interface will be loaded in the editor and added to the menu list.

  3. To edit an existing interface, select the interface from the drop down menu on the Interfaces tab.

  4. Edit the name, label, icon using the interface editor.

  5. Write Python code in the script text area which builds the interface. An onCreateInterface() function must be defined which returns the root widget of your interface. The returned root widget is embedded in the Python Panel.

  6. Save changes by pressing the Accept or Apply button.

Editing the Interface Menu

  1. Open the Python Panel Editor from the Windows menu or from the toolbar button in a Python Panel pane tab.

  2. Select the Edit Menu tab in the editor.

  3. Drag and drop available interface definitions from the list on the left and into the menu list on the right. Entries in the menu list can also be reordered using drag and drop. You can alternatively use the button to add entries to the menu and the button to remove entries. Multiple entries can be moved at the same time.

Deleting Interfaces

  1. Open the Delete Interfaces dialog from the Python Panel Editor or from the toolbar button in a Python Panel pane tab.

  2. In the dialog, select the interfaces to delete from the list. Multiple interfaces can be selected by holding the ⌃ Ctrl key during selection.

  3. Press the Delete button to the delete the selected entries. A confirmation dialog will display before entries are deleted.

Warning

The deletion process is irreversible since interface definitions are also deleted from disk. To remove entries from the interface menu without deleting the definitions, please refer to the Editing the Interface Menu section above.

Interfaces tab

The interfaces tab is used to create and edit Python interfaces. The drop down menu at the top can be used to select which interface to edit. New Interface creates a new interface and loads it into the editor. Delete Interface displays a dialog with a list of all interfaces that can be deleted.

Save To

The file path that the interface definition is saved to. The file must be writeable by Houdini for changes to be saved correctly. If the path is not writeable then an error message is displayed when attempting to apply changes to the interface. The file path can be typed manually or selected using the file browser on the right of the field.

Name

The internal name of the interface. This must be unique across all loaded Python interfaces. That is, at most one interface is loaded into for a given internal name. The name must start with a letter and can contain letters, numbers, and/or underscores.

Label

The human-readable name of the interface. The label is used in the Python Panel pane tab and in the menu interfaces menu. Multiple interfaces may share the same Label.

Icon

Internal name, file path, or URL of the icon to use for the interface.

Click the chooser button at the right end of the field to choose a file. Note that you can choose a file contained in a digital asset (click opdef: on the left side of the file chooser).

If you don’t supply an absolute path or URL, Houdini will look for the icon using the path in the $HOUDINI_UI_ICON_PATH environment variable.

You can use an SVG file or any image format Houdini supports (such as PNG or .pic). The icon image should be square.

Houdini ships with a number of stock SVG icons. You can see bitmap representations of these icons in $HFS/houdini/help/icons/large. To specify a stock icon, use the form dirname_filename, where…

  • dirname is the directory name under $HFS/houdini/help/icons/large, such as OBJ, SHELF, or MISC, and

  • filename is the icon’s filename minus any extension. For example, OBJ_sticky specifies the standard icon for the Sticky object.

Menu Hints

When no menu definition is loaded from disk then the interface menu hints are used to instruct Houdini on whether to include the interface in the menu and where to insert the interface into the menu.

Include in toolbar menu

Check this option to include the interface in the toolbar menu when no toolbar menu definition has been loaded from disk.

Menu position

The position where the interface should be inserted into the menu. The position is not absolute but instead relative to the specified positions of the other interfaces. For example, suppose there are three interfaces in Houdini – interface A with position 4, interface B with position 1 and interface C with position 25. Then interface B will appear first in the menu followed by A and then followed by C.

Create preceding separator

Check this option to create a separator immediately before the interface in the menu.

Include in pane tab menu

Check this option to include the interface in the panetab menu when no panetab menu definition has been loaded from disk.

Menu position

The position where the interface should be inserted into the menu. The position is not absolute but instead relative to the specified positions of the other interfaces. For example, suppose there are three interfaces in Houdini – interface A with position 4, interface B with position 1 and interface C with position 25. Then interface B will appear first in the menu followed by A and then followed by C.

Create preceding separator

Check this option to create a separator immediately before the interface in the menu.

Note

If a menu definition has been loaded from disk then Houdini will ignore the interface’s menu hints. In this case a warning will appear below the menu hints.

Script

The script definition for the Python interface. This is where PySide2 or PyQt5 code is written to build the interface. When the interface is loaded in a Python Panel, the script is executed and the root widget returned by the onCreateInterface() function is embedded into the panel.

Python Panels recognize and execute the following functions when certain events occur:

  • onCreateInterface()PySide2.QWidget or PyQt5.QWidget

    Executed when the Python Panel creates the Qt interface. The function must return the root Qt widget of the interface.

  • onDestroyInterface()

    Executed when the Python Panel is about to destroy the Qt interface. This can happen when the Python Panel pane tab is closed or if the interface is reloaded.

  • onActivateInterface()

    Executed when the interface becomes active and visible.

  • onDeactivateInterface()

    Executed when the interface becomes inactive and hidden.

Only the onCreateInterface() function is required by the interface. The other functions are optional.

Note

In older Houdini versions, the createInterface() function was required. This function is now deprecated and replaced by onCreateInterface().

Note

The kwargs dictionary is available in the interface script. The dictionary contains the following entries:

  • paneTab - The pane tab (hou.PaneTab) that contains the interface.

Here is an example of using kwargs in the script:

from PySide2 import QtWidgets

def onCreateInterface():
    panetab = kwargs["paneTab"]

    label = QtWidgets.QLabel()
    label.setText("Running in pane tab '%s'" % panetab.name())
    return label

Python Panel files

Python Panel menu and interface definitions are stored in .pypanel files on disk.

When Houdini starts up, it searches for .pypanel files in $HFS/houdini/python_panels and then in $HOUDINI_USER_PREF_DIR/python_panels by default and loads the definitions stored in those files.

If $HOUDINI_PATH is set, then Houdini instead searches for files in the python_panels subdirectory for each path listed in $HOUDINI_PATH.

You can override the search path by setting $HOUDINI_PYTHON_PANEL_PATH.

Note

Houdini loads .pypanel files in the order of the directories specified by $HOUDINI_PYTHON_PANEL_PATH and then in alphabetcial order by filename.

If multiple Python Panel interfaces with the same internal name are found on disk, then Houdini uses the last interface definition that it loaded.

Similarly, Houdini uses the last interfaces menu definition that it loaded.

Examples

Example name
Load

This example demonstrates how to link PySide2 parameter widgets (i.e. text fields and sliders) to Houdini node parameters and vice versa.

Load

This example demonstrates how to respond to drag and drop events from Houdini.

Load

This example demonstrates how to use a custom GraphicsScene subclass in a Python panel to make OpenGL calls.

Load

This example demonstrates how to handle widget events in a Python Panel.

Load

This example demonstrates how to load an interface created by Qt Designer.

Load

This example provides a PySide2 interface for editing viewport colors.

See also

Windows