Simple wxPython example(s)?

Could someone point me to (or post) a minimal example of wxPython integration? At the moment I have a Tkinter-based python console window, separate from my Panda3D window. All I’d like to do is have that console window be wx instead of Tkinter. That should allow me to use IPython as the shell as well (version 0.9.1 of IPython includes code for a wx-embedded shell).

I’ve done a bit of searching in the forums but mostly I’ve come up with posts showing much more sophisticated wx-based frameworks. These are very impressive but I’m looking for something much simpler, and ideally minimally invasive to my existing code.

Thanks!

Just put “want-wx #t” in your Config.prc (or call base.startWx() somewhere). Then, you can create your stuff using base.wxApp as app object.

Thanks for the quick reply!

Is that with 1.5.4? I’m having trouble figuring out how to get both the Panda and wx event loops running at the same time; if I do a run() I get Panda but no wx and if I do base.wxApp.MainLoop() then Panda doesn’t respond.

Could you post/point me at a minimal working example?

Thanks again!

You don’t need to call MainLoop on the wxApp - it is supposed to be called automatically.
If just run() doesn’t work, make sure you’ve called base.startWx() early enough (or placed want-wx #t in Config.prc).

Here’s the code I have at present:

import wx
import direct.directbase.DirectStart
base.startWx()

foo=loader.loadModel('misc/rgbCube')
foo.reparentTo(render)

class MainWindow(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'Test', size=(300,200))
        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(sizer)
        txt = wx.StaticText(panel, -1, 'Hello World!')
        sizer.Add(txt, 0, wx.TOP|wx.LEFT, 20)
        self.but = wx.Button(panel, label="Foo!")
        self.but.Bind(wx.EVT_BUTTON, self.onButton)
        sizer.Add(self.but, 0, wx.TOP|wx.LEFT, 20)
        self.Centre()
        self.Show(True)
        
    def onButton(self, event):
        print 'Button clicked!'
        
mw = MainWindow(None)

run()

If I run this with the python interpreter:

python pandawx.py

… I get a Panda3D window which responds as expected, but no wx window in sight. Interestingly, if I start it with IPython:

ipython -wthread pandawx.py

… then the same thing happens at first. But then if I go back to the terminal and hit Ctrl+C, the wx window then appears, and is responsive. If I then enter run() on the IPython commandline, then I have what I want: Panda3D and wx both responding.

bump… Can anyone point out what’s wrong with my code?

I have my own python and wxpython is installed in my own python. Your code is running well on my machine, Windows XP.

@clcheung: Hmm, that’s interesting. Thanks for checking. Do you mind telling me what versions of python, wx, and panda you are using?

I can run it on panda 1.5.4 and 1.6.1
My python is 2.5
wxPython 2.8.4

I think this is more of a configuration issue for your problem, rather than software compatibility.

Are you able to run other wxpython programs samples ?
e.g. my demomaster
discourse.panda3d.org/viewtopic … highlight=

or Panda3D Samples Dojo WX [less early stage@2009-03-23]
discourse.panda3d.org/viewtopic.php?t=5728

or this small sample:
discourse.panda3d.org/viewtopic … highlight=

pbouf, do not use the link under Panda3D Samples Dojo WX [less early stage@2009-03-23] 'cos there are still many issues and is so bloated to be used for learning purposes.
Take a peek into this instead: it is lighter and newer therefore less buggy - if you’ll find hard to understand something drop a line in that thread and I’ll try to help you.

I ran your code as well, It ran fine on latest wxpy/P3D 1.5.4

@astelix: Thanks, yes I’d seen your p3dwxpod (very nice!) but actually what I want to do is not as ambitious: I want to keep the Panda3D window separate but I also want to have some wx windows as part of the same app. In particular I’m hoping to get the new wx-based IPython shell integrated. IPython is by far my favourite interactive environment but right now I have to Ctrl+C to interrupt Panda3D, enter commands in IPython, then type run(), etc…

What I’d really like to be able to do is have a master class like this:

from PandaWindow import PandaWindow
from WxGui import WxGui
import WxPandaGlue

class MyApp:
    def __init__(self):
        self.pandastuff = PandaWindow()
        self.wxgui = WxGui()
        WxPandaGlue.magic_glue_function(self.wxgui, self.pandastuff)

… so what I’m struggling to understand is what would I need to do in WxPandaGlue to make this work?

I can’t see why my pod don’t suite your needs - it is indeed conceived to be a shell like you’re searching for - just try to tellme what kind of stuff you want to do with it and I’ll tellya if shall and how to do it with the pod.

@astelix: Probably your module can do it, I’m just trying to keep things as simple as possible. But my last post pretty much sums up what I want: Panda3D graphics view in its own window (though that’s mostly because at the moment I’m suffering that ATI bug that we’re talking about in the other thread) and a wx GUI in another. The GUI will feature a tabbed interface, menus, splitter, etc. And of course the IPython prompt as I was describing. The interaction between the GUI and 3D windows is minimal; the GUI is used to enter the inputs for some engineering calculations and the 3D elements are updated when those inputs change.

For the moment if you could show me a way to make the 3D window external to the wx GUIs then I could probably go forward.

Thanks for all your help!

I read your last post but you talk about things (whats a WxPandaGlue?) I don’t know, sorry. Maybe this IDE could be something closer to what you’re looking for?
If not, the cheung demomaster cited above works as you say with the usual P3d window detached, give it a peek.

@astelix: Sorry, I guess I’m not being very clear. The code I posted was really pseudo-code to try (I guess unsuccessfully) to illustrate my point. Basically I’d just like to know what is “the secret” to getting Panda3D and Wx to live happily together. I’d rather not have to reuse any significant amount of code; I already have enough dependencies in my project. I could probably figure it out by examining your code, and I have spent some time at that, but so far I still haven’t figured it out.

So I’m hoping “the secret” is actually pretty simple and you could share it with us. :slight_smile:

Thanks again.

so that was all about? I guessed you already passed by this well renown thread (that was where I started out) but looks like you oversighted it
As you can see, no secrets here :wink:

Aha! I knew I must have been missing something simple. I do recall that thread and I think I even tried it but had problems which I think were related to the GLXBadDrawable issue solved in discourse.panda3d.org/viewtopic.php?p=30185. But for whatever reason I didn’t try to troubleshoot it then.

So, here’s what I’ve got:

"""
wxPandaIPShell.py

Based on code from 'drwr' (https://discourse.panda3d.org/viewtopic.php?p=15431)
This version keeps the Panda3D window separate, and provides an IPShellWidget
in the wx window.
In the IPython shell, the local var 'self' has been set to refer to the
App instance. base, render, loader, etc from Panda are all there as well
since they show up as builtins.
"""
import wxversion
wxversion.select('2.8')
import wx

from direct.directbase.DirectStart import *
from direct.showbase import DirectObject

from IPython.gui.wx.ipython_view import IPShellWidget

class App(wx.PySimpleApp, DirectObject.DirectObject):
    def __init__(self):
        wx.PySimpleApp.__init__(self)
        #Create a new event loop (to overide default wxEventLoop)
        self.evtloop = wx.EventLoop()
        self.old = wx.EventLoop.GetActive()
        wx.EventLoop.SetActive(self.evtloop)
        taskMgr.add(self.wx, "Custom wx Event Loop")

    # wxWindows calls this method to initialize the application
    def OnInit(self):
        self.SetAppName('My wx app')
        self.SetClassName('MyAppClass')

        self.parent = wx.MDIParentFrame(None, -1, 'My wx app')
        self.child = wx.MDIChildFrame(self.parent, -1, 'IPShell')

        self.parent.SetClientSize((600, 400))
        self.parent.Show(True)
        self.child.SetClientSize((400, 300))
        self.child.Show(True)
        self.ipShell = IPShellWidget(self.child)
        self.ipShell.IP.updateNamespace(dict(self = self))
        base.setFrameRateMeter(True)
        return True

    def wx(self, task):
        while self.evtloop.Pending():
            self.evtloop.Dispatch()
        #time.sleep(0.01)
        self.ProcessIdle()
        return task.cont

    def close(self):
        wx.EventLoop.SetActive(self.old)

app = App()
run() 

so we may say ‘case closed’ then. I’m glad you did it
sometime I’d to dig into that IPShellWidget - looks interesting, even if actually I can’t see for what.