not sure if this is the right place for such question, but I need some help, ShowModal() causes panda3d, inside a wxDialog, to get stuck, it does not render nothing and the screen is black.
ShowModal --> Note that this function creates a temporary event loop which takes precedence over the application’s main event loop (see wxEventLoopBase) and which is destroyed when the dialog is dismissed
I think this temporary event loop that interrupts panda.
Yes, I agree with your diagnosis. The best solution, I think, is not to use ShowModal(). That function is designed to pause the entire application, so it is behaving exactly as designed.
dialog = Widgets.Dialog()
# safely start modal dialog and keep Panda running
def onTimer(event):
try:
base.taskMgr.step()
except:
pass
pandaTimer = wx.Timer(dialog, - 1)
dialog.Bind(wx.EVT_TIMER, onTimer, id = pandaTimer.GetId())
# keep FPS resonable, smaller value make Wx unresponsive
pandaTimer.Start(35)
dialog.ShowModal()
and I got this response:
Assertion failed: _num_busy_threads == 0 at line 865 of c:\p\p3d\panda3d-1.6.2\panda\src\event\asyncTaskChain.cxx
another attempt: I used the Show() function instead ShowModal() and I wrote a basic task that calls dialog.SetFocus() and returns task.cont, almost there but the wx.Frame continues to respond to events such as mouse clicks or menu selections or button clicks! Next step is to avoid those events while the dialog does not exit. Not sure if this is a fine solution.
You can’t call TaskManager step in context of another one.
That is why I created my own loop calling Panda and Wx
one after another instead of processing Wx events in Panda
context.
def run():
while True:
base.taskMgr.step()
wxStep()
time.sleep(0.001)
With this custom loop you can in Wx context call modal windows and run Panda’s task manager periodically with timer.
If you need to do the same in Panda context use wx.CallAfter:
def callDialog(res):
dlg = MyDialog()
ret = pandaShowModalDialog(dlg)
dlg.Destroy()
res[0] = True
res[1] = ret
def myContinuation(val):
# do something
pass
def waitDialogTask(cont, dialogRet):
finished, result = dialogRet
if finished:
cont(result)
return None
else:
return Task.cont
res = [False, None]
wx.CallAfter(callDialog, res)
taskMgr.add(waitDialogTask, 'MyDialogTask', extraArgs=[myContinuation, res])
You can disable/enable temporary main Wx window with win.Enable(False/True) but there is another problem.
When you use Show you must handle dialog
controls by yourself.
All standard Wx dialogs become useless becouse their controls
are not exported to Python level.