How to setup panda and wxpython?

Return to Scripting Issues

How to setup panda and wxpython?

Postby macromate » Wed Apr 18, 2012 9:59 am

Hi,
I recently started using panda 1.8 and I'm excited about the better wxpython support (especially for Mac OSX). However I can't figure out how to use it. I managed to set up wxpython and the direct.wxwidgets.WxPandaWindow class and the result looks like this:

Image

But I can't move the camera and it seams as if the panda app receives no events at all. I guess I set it up wrong, but i can't find a offical way of doing it. Can you please help me?

This is my current code (some of it):



Code: Select all
import wx
import wx.aui

from direct.showbase.ShowBase import ShowBase
from direct.wxwidgets.ViewPort import Viewport
import panda3d.core as core

core.loadPrcFileData('startup', 'window-type none')

class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.auiManager = wx.aui.AuiManager(self)
       
        self.panda = Viewport.makeFront(self)
        self.outliner = scenegraph.Panel(self)
       
        outlinerInfo = wx.aui.AuiPaneInfo().Name("outliner")
        outlinerInfo.Left().CloseButton(False)
        outlinerInfo.Caption("Scenegraph").BestSize((300, 300))
        self.auiManager.AddPane(self.outliner, outlinerInfo)
       
        pandaInfo = wx.aui.AuiPaneInfo().Name("panda")
        pandaInfo.Center().CloseButton(False).MaximizeButton(True)
        self.auiManager.AddPane(self.panda, pandaInfo)
           
        self.auiManager.Update()
   
    def onQuit(self, evt):
        self.auiManager.UnInit()
        self.Close()

class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self, fStartDirect=False, windowType=None)       
        # setup application window       
        self.startWx()
        self.wxApp.Bind(wx.EVT_CLOSE, self.quit)
        self.frame = Frame(None, wx.ID_ANY, 'Editor', size=(1024, 768))
        self.frame.Show()
       
        # setup mouse/picking/selection system

        # THIS DOES NOT WORK,
        # neither pressing the left/right mouse button
        # nor pressing t outputs "debug"
        def foo():
            print "debug"
        self.accept("mouse1", foo)
        self.accept("mouse3", foo)
        self.accept("t", foo)


        # load the scene (set up models and stuff)
        self.loadScene(self.args.map)

    def quit(self, event=None):
        self.onDestroy(event)
        try:
            base
        except NameError:
            sys.exit()
        base.userExit()

app = App()
app.run()



Thanks !

PS: I'm using Panda 1.8 and wxpython 2.9.3.1 on Windows 7.
Last edited by macromate on Fri Apr 20, 2012 5:52 pm, edited 1 time in total.
macromate
 
Posts: 8
Joined: Sun Jul 24, 2011 12:01 pm

Postby rdb » Wed Apr 18, 2012 1:42 pm

Hmm, if you put a print statement in ShowBase.py function __wxTimerCallback, does it show up? That would tell us if the timer that is supposed to run the Panda event loop is running properly at all.
rdb
 
Posts: 8558
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby macromate » Wed Apr 18, 2012 4:01 pm

I checked this and __wxTimerCallback gets called.
macromate
 
Posts: 8
Joined: Sun Jul 24, 2011 12:01 pm

Postby rdb » Fri Apr 20, 2012 3:14 am

If you put "base.messenger.toggleVerbose()", and try and send events to the Panda window, how do they appear (if at all) on the console?
rdb
 
Posts: 8558
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby macromate » Fri Apr 20, 2012 4:06 am

I enabled base.messenger.toggleVerbose() and there are numerous log messages printed as the app is loading:

Code: Select all
C:\open-emergency>python editor
Verbose mode true.  quiet list = ['collisionLoopFinished', 'event-loop-done', 'NewFrame', 'avatarMoving']
C:\Panda3D-1.8.0\direct\showbase\ShowBase.py:2740: wxPyDeprecationWarning: Using deprecated class.
  self.wxApp = wx.PySimpleApp(redirect = False)
Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
:display:windisplay(warning): SetActiveWindow() failed!
:display:windisplay(warning): SetForegroundWindow() failed!
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask resetPrevTransform], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask dataLoop], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask ivalLoop], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask collisionLoop], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask garbageCollectStates], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask igLoop], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask audioLoop], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask eventManager], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x064A5AD0>], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x064A5AB8>], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x064A5AD0>], taskChain = None
:Messenger(debug): sent event: open_window sentArgs = [<libpanda.GraphicsWindow object at 0x064A5A70>, True], taskChain = None
:Messenger(debug): sent event: open_main_window sentArgs = [], taskChain = None
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: tree-item-added
 method: <bound method Tree.onItemAdd of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: tree-item-deleted
 method: <bound method Tree.onItemDelete of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: tree-item-hidden
 method: <bound method Tree.onItemVisibilityChange of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: tree-item-unhidden
 method: <bound method Tree.onItemVisibilityChange of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: selection-empty
 method: <bound method Tree.UnselectAll of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: selection-changed
 method: <bound method Tree.onSelectionChange of <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> >>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.scenegraph.Tree; proxy of <Swig Object of type 'wxPyTreeCtrl *' at 0x6195820> > (('Tree', 5))
 accepting: map-loading-finished
 method: <function <lambda> at 0x064BF2F0>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.App instance at 0x019043F0> (('App', 1))
 accepting: mouse1
 method: <function foo at 0x066B2A70>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.App instance at 0x019043F0> (('App', 1))
 accepting: mouse3
 method: <function foo at 0x066B2A70>
 extraArgs: []
 persistent: 1
:Messenger(debug): object: <editor.App instance at 0x019043F0> (('App', 1))
 accepting: t
 method: <function foo at 0x066B2A70>
 extraArgs: []
 persistent: 1
:Messenger(debug): sent event: map-loading-finished sentArgs = [], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x06BE48D8>], taskChain = None
:Messenger(debug): sent event: aspectRatioChanged sentArgs = [], taskChain = None
:Messenger(debug): sent event: TaskManager-addTask sentArgs = [PythonTask manager-update], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x06BE48C0>], taskChain = None
:Messenger(debug): sent event: aspectRatioChanged sentArgs = [], taskChain = None
:Messenger(debug): sent event: window-event sentArgs = [<libpanda.GraphicsWindow object at 0x064A5EF0>], taskChain = None
:Messenger(debug): <direct.showbase.Loader.Loader instance at 0x06386D00> (('Loader', 0))
 now ignoring: 'async_loader_0'



However, pressing left/right mouse or pressing "t" doesn't produce any log message. When I resize the window, "aspectRatioChanged" messages are sent.

Then I added messenger.send("t") after self.LoadScene and this works. foo() gets called and debug is printed to the console, as well as this log message:
Code: Select all
:Messenger(debug): sent event: t sentArgs = [], taskChain = None
macromate
 
Posts: 8
Joined: Sun Jul 24, 2011 12:01 pm

Postby rdb » Sat Apr 21, 2012 9:25 am

That is strange. Something in wxPython must be preventing the events from being sent to the Panda window. I don't know enough about wxPython to say what, though.
rdb
 
Posts: 8558
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby macromate » Sat Apr 21, 2012 11:49 am

Are you sure? I managed to get it working after a few changes in EmbeddedPandaWindow. I found this somewhere in the forum and it works like a charm.

Code: Select all
class EmbeddedPandaWindow(wx.Window):
    """ This class implements a Panda3D window that is directly
    embedded within the frame.  It is fully supported on Windows,
    partially supported on Linux, and not at all on OSX. """

    def __init__(self, *args, **kw):
        gsg = None
        if 'gsg' in kw:
            gsg = kw['gsg']
            del kw['gsg']

        base.startWx()
        wx.Window.__init__(self, *args, **kw)

        wp = WindowProperties.getDefault()
        if platform.system() != 'Darwin':
            try:
                wp.setParentWindow(self.GetHandle())
            except OverflowError:
                # Sheesh, a negative value from GetHandle().  This can
                # only happen on 32-bit Windows.
                wp.setParentWindow(self.GetHandle() & 0xffffffff)

        #
        # CHANGE HERE
        # self.win = base.openWindow(props = wp, gsg = gsg, type = 'onscreen', unexposedDraw = False)
        base.openDefaultWindow(props=wp, gsg=None)
        self.win = base.win
        #
       
        self.Bind(wx.EVT_SIZE, self.onSize)

        # This doesn't actually do anything, since wx won't call
        # EVT_CLOSE on a child window, only on the toplevel window
        # that contains it.
        self.Bind(wx.EVT_CLOSE, self.__closeEvent)

    def __closeEvent(self, event):
        self.cleanup()
        event.Skip()

    def cleanup(self):
        """ Parent windows should call cleanup() to clean up the
        wxPandaWindow explicitly (since we can't catch EVT_CLOSE
        directly). """
        if self.win:
            base.closeWindow(self.win)
            self.win = None

    def onSize(self, event):
        wp = WindowProperties()
        wp.setOrigin(0, 0)
        wp.setSize(*self.GetClientSize())
        # CHANGE HERE
        self.win.requestProperties(wp)
        #
        event.Skip()


What do you think of this? Could it be that the issue is not caused by wxPython but by Panda? The rest of my code stayed the same, I just replaced

Code: Select all
self.panda = Viewport.makeFront(self)

with
Code: Select all
self.panda = WxPandaWindow(self)
macromate
 
Posts: 8
Joined: Sun Jul 24, 2011 12:01 pm

Postby drwr » Tue Apr 24, 2012 2:02 pm

Are you sure you needed to make the change to EmbeddedPandaWindow? I think it would work without that change, as long as you replaced your call to Viewport with a call to WxPandaWindow.

I think Viewport makes a lot of other assumptions that aren't true in your case, but WxPandaWindow is closer to your environment.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Sat May 12, 2012 1:02 pm

When I try to run this as a test I get:

.../demo.py
activate_osx_application
This program needs access to the screen.
Please run with 'pythonw', not 'python', and only when you are logged
in on the main display of your Mac.


I have secondary display hooked up to my iMac, is that it? Not sure if I want to deactivate it and reboot the computer.
iMac (2009), Mac OS X.8.1 - MacBookPro (2007), Mac OS X.8.2
@ YouTube
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Thu May 17, 2012 11:21 am

Did you try running it with pythonw instead of python, as it suggests? E.g. "pythonw demo.py"?

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Thu Jun 14, 2012 3:34 pm

That gives:
Code: Select all
Traceback (most recent call last):
  File "/Applications/Panda3D_Mare_Ceti/samples/WXPython/demo1.py", line 3, in <module>
    import wx
  File "/var/tmp/wxWidgets/wxWidgets-13~231/2.6/DSTROOT/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/wx-2.8-mac-unicode/wx/__init__.py", line 45, in <module>
  File "/var/tmp/wxWidgets/wxWidgets-13~231/2.6/DSTROOT/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/wx-2.8-mac-unicode/wx/_core.py", line 4, in <module>
ImportError: /System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/wx-2.8-mac-unicode/wx/_core_.so: no appropriate 64-bit architecture (see "man python" for running in 32-bit mode)


python? ppython? pythonw? Oh man ... :shock:
iMac (2009), Mac OS X.8.1 - MacBookPro (2007), Mac OS X.8.2
@ YouTube
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

same problem -- a clue?

Postby doublereedkurt » Mon Aug 13, 2012 3:20 am

I am having the same problem in windows.

I noticed that the ShowBase object's mouseWatchNode is set to None.

Maybe there is some critical initialization which is not happening? Maybe there is a way to do it manually?

EDIT:
Is this necessary?
core.loadPrcFileData('startup', 'window-type none')

I'll bet the initialization of some of the input handlers doesn't happen until the window exists.

Hmm... Further investigation:

The bottom of this page http://www.panda3d.org/manual/index.php/SPE

recommends that if the window-type is set to none, the window can be started later with this function:
base.openMainWindow(type = 'onscreen')

The docs for that function (ShowBase.openMainWindow) say:
Creates the initial, main window for the application, and sets up the mouse and render2d structures appropriately for it.

So, maybe input handlers are not being properly initialized because the window is not started?


EDIT 2:

If I omit the line
core.loadPrcFileData('startup', 'window-type none')
then two windows show: the wxPython window, and the regular Panda3D window.

Input works in the Panda window, but not in the wxPython window.

class MainWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Test', size=(640, 480))
self.panda_panel = WxPandaWindow(parent=self)
self.Show(True)

EDIT 3:
Source code here: http://panda3d.cvs.sourceforge.net/view ... xt%2Fplain

I need to read and understand what is going on there to track it down... looks like suppressing the window-open is the correct thing to do, since ther eis a call to base.openWindow inside the EmbeddedPandaWindow.
doublereedkurt
 
Posts: 10
Joined: Sun Jul 15, 2012 11:39 pm

Postby rdb » Wed Aug 15, 2012 5:01 am

@Bradamante: it looks like there's a mismatch between the architecture of your wx installation and the version of Python you're running.

@doublereedkurt: on some platforms, wx wants control over the main loop in order for events to work properly. In 1.8.0 and above, this is done by Panda if you put "want-wx #t" in Config.prc (or use base.startWx()). Does that help?
rdb
 
Posts: 8558
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby doublereedkurt » Wed Aug 15, 2012 12:44 pm

@rdb: thanks, I didn't know what startWx() did; it is being called so that probably isn't the problem.

That is an interesting avenue though, I'll try adding some wxPython widgets to the frame as well, and see if they are getting keyboard/mouse events.

I notice looking at the source code of WxPandaWindow that the windows class is much, much smaller than the OpenGL class. I wonder if some of that extra code is for passing through mouse/keyboard events when the panda window has focus.

Edit:
Ok, clearly the extra code has to do with passing through input events. The real question is, is that necessary for non-OpenGL windows? I'll try Bind()'ing mouse and keyboard handlers on the window through wxPython's normal mechanisms. Actually, it wouldn't be too much code to have a pass-through binding. The only tricky part will be getting accurate screen coordinates for mouse clicks.

Also, I notice the aspect ratio doesn't change when the window is re-sized.
doublereedkurt
 
Posts: 10
Joined: Sun Jul 15, 2012 11:39 pm

Postby ynjh_jo » Wed Aug 15, 2012 8:25 pm

You haven't created any panda window at all, that's what.
Stripped down version, beware :
Code: Select all
import wx
import wx.aui

from direct.showbase.ShowBase import ShowBase
from direct.wxwidgets.ViewPort import Viewport
import panda3d.core as core

core.loadPrcFileData('startup', 'window-type none')

class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.auiManager = wx.aui.AuiManager(self)
       
        self.panda = Viewport.makeFront(self)
 
        pandaInfo = wx.aui.AuiPaneInfo().Name("panda")
        pandaInfo.Center().CloseButton(False).MaximizeButton(True)
        self.auiManager.AddPane(self.panda, pandaInfo)
           
        self.auiManager.Update()
   
    def onQuit(self, evt):
        self.auiManager.UnInit()
        self.Close()

class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self, fStartDirect=False, windowType=None)       
        # setup application window       
        self.startWx()
        self.wxApp.Bind(wx.EVT_CLOSE, self.quit)
        self.frame = Frame(None, wx.ID_ANY, 'Editor', size=(800, 600))

        # YNJH : create P3D window
        wp = core.WindowProperties()
        wp.setOrigin(20,20)
        wp.setSize(400,300)
        wp.setParentWindow(self.frame.panda.GetHandle())
        base.openMainWindow(type = 'onscreen', props=wp)

        self.frame.Show()
       
        # setup mouse/picking/selection system

        def foo():
            print "debug"
        self.accept("mouse1", foo)
        self.accept("mouse3", foo)
        self.accept("t", foo)

    def quit(self, event=None):
        self.onDestroy(event)
        try:
            base
        except NameError:
            sys.exit()
        base.userExit()

app = App()
app.run()
http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | ATI Radeon HD4670 1GB GDDR3
User avatar
ynjh_jo
 
Posts: 1795
Joined: Tue Apr 18, 2006 12:41 am
Location: Malang, Indonesia

Postby doublereedkurt » Wed Aug 15, 2012 10:09 pm

@ynjh_jo

That makes a lot of sense!
Thank you so much :-)
doublereedkurt
 
Posts: 10
Joined: Sun Jul 15, 2012 11:39 pm

Postby doublereedkurt » Thu Aug 16, 2012 11:44 pm

Alright, so apparently WxPandaWindow / EmbeddedPandaWindow calls base.openWindow(). When you call openWindow() you get something without input handlers.

So, basically TLDR; if you want to enclose your game inside a wxWindows frame, it is totally doable, but you'll have to do it manually and just use WxPandaWindow as a starting point.
doublereedkurt
 
Posts: 10
Joined: Sun Jul 15, 2012 11:39 pm

Re: How to setup panda and wxpython?

Postby gyedo » Wed Mar 20, 2013 6:17 pm

@Bradamante

Try to use /usr/bin/pythonw2.5
User avatar
gyedo
 
Posts: 29
Joined: Fri Jun 22, 2007 12:46 pm
Location: Glendale, CA


Return to Scripting Issues

Who is online

Users browsing this forum: Google [Bot] and 1 guest