Keeping Panda running behind wxPython modal dialog

When the following code runs, it draws a cube and constantly updates its orientation. Whenever you click, a wxPython modal dialog will pop up, and Panda will suddenly stop updating the frame. It’s also kind of weird that even though it looks like nothing is happening, when the dialog goes away, the frame has advanced anyhow!

import sys
import wx
import direct.directbase.DirectStart
from direct.task import Task
from direct.showbase import DirectObject
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import LerpHprInterval
import time

class PandaGui(DirectObject.DirectObject):

    def __init__(self):
        # set up Panda low-level configuration
        loadPrcFileData('startup', 'window-type none')
        loadPrcFileData('startup', 'aux-display tinydisplay')
        loadPrcFileData('yield-timeslice', '#t')
        loadPrcFileData('sync-video', '#f')
        loadPrcFileData('win-origin', '0 0')

        # replace wx event loop with custom one
        self.wxgui = wx.PySimpleApp()
        self.evtloop = wx.EventLoop()
        self.oldWxEventLoop = wx.EventLoop.GetActive()
        wx.EventLoop.SetActive(self.evtloop)
        taskMgr.add(self.wx_loop, 'Custom wx event loop')

        # link panda to the wx frame and set some properties
        self.frame = wx.Frame(None, wx.ID_ANY, 'Title')
        self.frame.SetClientSize((200, 200))
        windowProps = WindowProperties.getDefault()
        windowProps.setOrigin(-300, -200)
        windowProps.setForeground(False)
        windowProps.setParentWindow(self.frame.GetHandle())
        base.openDefaultWindow(props=windowProps)
        base.accept('mouse1', self.popup)

        self.frame.Bind(wx.EVT_CLOSE, lambda x:sys.exit(0))
        self.frame.Show(True)

        base.camera.setY(-30)
        model = loader.loadModel('models/misc/rgbCube')
        model.reparentTo(render)

        lerp = LerpHprInterval(model, 3, \
                      (model.getH() + 180, model.getP(), \
                      model.getR()), model.getHpr())
        lerp.loop()

    def popup(self):
        dialog = wx.MessageDialog(self.frame, \
                      "Wouldn't it be nice if Panda wasn't hung?", \
                      'A modal dialog')
        dialog.ShowModal()
        dialog.Destroy()

    def wx_loop(self, task):
        while self.evtloop.Pending():
            self.evtloop.Dispatch()
        self.wxgui.ProcessIdle()
        time.sleep(0)
        return Task.cont

if __name__ == '__main__':
    gui = PandaGui()
    run()

I realize the event loop as defined in PandaGui.wx_loop() doesn’t let the task end until wx says it’s done, so something has to change there probably. I’ve tried one or two small things but nothing worked. Any ideas? Thanks in advance!

The very definition of ShowModal() is that it doesn’t return until the dialog is gone. So in all that time, Panda isn’t updating, because your function hasn’t returned. Then when you do finally close the dialog, Panda gets a chance to update, and it sees that a lot of time has elapsed and advances the animation appropriately.

If you want Panda to continue to update while a dialog is visible, you have to use Show(), not ShowModal().

David