super short panda and wxpython

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from math import pi, sin, cos
import sys, time, wx
import threading


class wxThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.messages = []

    def run(self):
        # setup wxPython window
        self.wxApp = wx.App(False)
        wxMainApp(None, self, "wxpython and Panda3d")
        self.wxApp.MainLoop()

    def shutdown(self):
        self.wxApp.Destroy()
        sys.exit()

    def putMessage(self, msg):
        self.messages.append(msg)

    def getMessage(self):
        try:
            return self.messages.pop()
        except:
            return None


# wxPython Window
class wxMainApp(wx.Frame):
    def __init__(self, parent, instance, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title=title, pos=(860,20), size=(200,638))
        self.PandaApp = instance

        # Status Bar, just because
        self.CreateStatusBar()

        # add a panel and sizer for the frame so we can stick controls into it
        panel = wx.Panel(self)
        box = wx.BoxSizer(wx.VERTICAL)

        # add a button
        self.button1 = wx.Button(panel, id=1000, label='Button', pos=(8, 8), size=(60,60))
        self.button1.Bind(wx.EVT_BUTTON, self.SendPandaMessage)
        box.Add(self.button1, 0, wx.ALL, 10)

        # a text control
        self.control = wx.TextCtrl(panel, pos=(8, 100), size=(176,200), style=wx.TE_MULTILINE)
        box.Add(self.control, 0, wx.ALL, 10)

        # and finally, bind the close event
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        # and show everything
        self.Show(True)

    def OnClose(self, evt):
        msg = 'CLOSE', evt.GetId()
        self.PandaApp.putMessage(msg)

    def SendPandaMessage(self, evt):
        msg = 'CLICK', evt.GetId()
        self.PandaApp.putMessage(msg)


# Panda Render Window
class PandaApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # start wx control window in it's own thread
        self.wxApplication = wxThread()
        self.wxApplication.start()

        # load demo environment model, scale and position, from Hello World
        self.environ = self.loader.loadModel("models/environment")
        self.environ.reparentTo(self.render)
        self.environ.setScale(0.25, 0.25, 0.25)
        self.environ.setPos(-8, 42, 0)
        self.angle = 6.0
        
        # add spin camera task
        self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")
        # add message pump task - Panda runs this every frame
        self.taskMgr.add(self.getAppMessage, "getAppMessage")

    # Panda Task - query wxApplication message que
    def getAppMessage(self, task):
        self.processMessage(self.wxApplication.getMessage())
        return Task.cont

    # and do whatever here
    def processMessage(self, message):
        if message != None:
           print message
           if message[0] == 'CLICK':
              self.angle = self.angle + 1.0     #mod this from button click in wxpython
           if message[0] == 'CLOSE':
              self.wxApplication.shutdown()     #our wxpython is closing, kill everything
        
    # procedure to spin the camera.
    def spinCameraTask(self, task):
        angleDegrees = task.time * self.angle   #and use it here
        angleRadians = angleDegrees * (pi / 180.0)
        self.camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 3)
        self.camera.setHpr(angleDegrees, 0, 0)
        return Task.cont

# start everything
panda = PandaApp()
run()