Houdini 12 Python Scripting with the Houdini Object Model HOM Cookbook

Overview

This example illustrates how to use the wxPython user interface widget toolkit to create a custom user interface inside Houdini by invoking wxPython’s event loop from Houdini’s event loop. Houdini does not distribute wxPython, so if it is not installed you need to install it to your Python distribution. On Windows, install to $HFS/python.

Location

Supporting files for this example are in $HFS/houdini/help/hom/cookbook/wxPython, also found in the cookbook/wxPython directory of cookbook_files.tar.gz.

Running the Example

Create a shelf tool containing the following and launch it. It will pop up a window with a button and some text. Clicking on the button will display a font chooser dialog that controls the font for the text.

import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(400, 100))

        # Add a panel to the window.
        main_panel = wx.Panel(self, wx.NewId())
        main_panel.SetSizer(wx.BoxSizer(wx.VERTICAL))

        # Add a subsizer to lay out controls from left-to-right.  Set
        # proportion to 1 so that the subsizer stretches out vertically and set
        # flag to wx.ALIGN_CENTER so that all the controls added to the
        # subsizer are centered horizontally.
        horiz_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_panel.GetSizer().AddSizer(
            horiz_sizer, proportion=1, flag=wx.ALIGN_CENTER)

        # Add a button to the panel.  When clicked, it will open wxPython's
        # default font chooser dialog.
        font_button = wx.Button(main_panel, wx.NewId(), "Change Font...")
        horiz_sizer.Add(font_button, flag=wx.ALIGN_CENTER_VERTICAL)

        # Add some horizontal spacing between the controls.
        horiz_sizer.AddSpacer((10, 1))

        # Add a label to the panel.
        self.myLabel = wx.StaticText(
            main_panel, wx.NewId(), "This is some Sample Text.")
        horiz_sizer.Add(self.myLabel, flag=wx.ALIGN_CENTER_VERTICAL)

        # Create a font chooser dialog that's hidden by default but will open
        # when the user clicks "Change Font...".
        self.fontChooserDialog = wx.FontDialog(self, wx.FontData())

        # Register the button-click event handler and open this window.
        wx.EVT_BUTTON(self, font_button.GetId(), self.onButtonClicked)
        self.Show(True)

    def onButtonClicked(self, event):
        result = self.fontChooserDialog.ShowModal()

        # If the user clicked on the "OK" button then change the label's font
        # to the one selected in the dialog.
        if result == wx.ID_OK:
            font_data = self.fontChooserDialog.GetFontData()
            font = font_data.GetChosenFont()
            self.myLabel.SetFont(font)

def runWxApp(app, window):
    """Call this function with the application and the toplevel window instead
       of calling app.MainLoop.  Note that this function returns right away.
       Also note that this function is independent of this example, and you
       could factor it out into its own module."""
    def processWxEvents():
        """Houdini runs this callback to from its event loop to process wx
           events."""
        while event_loop.Pending():
            event_loop.Dispatch()
            app.ProcessPendingEvents()

    def onClose(event):
        """We bind this callback to the window's close event to destroy the
           window and stop the wx event loop."""
        window.Show(False)
        window.Destroy()
        processWxEvents()
        hou.ui.removeEventLoopCallback(processWxEvents)
    window.Bind(wx.EVT_CLOSE, onClose)

    event_loop = wx.EventLoop()
    wx.EventLoop.SetActive(event_loop)
    hou.ui.addEventLoopCallback(processWxEvents)

app = wx.PySimpleApp()
frame = MainWindow(None, "Font Dialog")
runWxApp(app, frame)