MenuBars

I want to have standard menus (in the menubar) for my panda application, and I need it to be cross platform (at the very least, mac and windows support).

I’ve looked at tkwidgets and wxwidgets that come with panda. wx just throws an:
wx._core.PyNoAppError: The wx.App object must be created first!
error if I make an wxAppShell, and tkwidgets puts up 2 windows that never get any time and thus nothing can be done with them.

I’m sure there should be some documentation somewhere on how to use these with panda, but I can’t find it.

Any suggestions on how I should proceed on trying to get the menubar to work?

I’d like to also free myself from panda’s full out screen refreshing and manually control when the frames are re-rendered. How do I do this?

I think to control the frame rendering, use taskmgr.step() instead of run().

You do have to create your own wx.App() in order to use wxPython. That’s just part of the rules for using wxPython, it has nothing to do with Panda. But if you call base.startWx(), it will create that app for you and store it in base.wxApp, and it will also spawn a task that keeps wxPython refreshed in sync with the Panda task loop.

If you want to stop the frame from rendering, you could stop the entire task loop as zhao suggests, but you might want those tasks to continue to run (especially if one of them is also refreshing wxPython). So another approach would be to remove the ‘igLoop’ task, and call base.graphicsEngine.renderFrame() explicitly; or to simply disable the window with base.win.setActive(False), and re-enable it when you’re ready for it to render again.

David

Thanks for the tips. Having all the wx stuff in the documentation lead me to believe wx was included with panda. Apparently this is not the case. Perhaps the documentation could use an update?

Anyway, here is the basics to get wx going:

from direct.showbase.ShowBase import ShowBase
import direct.directbase.DirectStart
from direct.wxwidgets import WxAppShell
base.startWx()

s=WxAppShell.WxAppShell()

run()

Lets me get a nice about box (accessible from one of the two help menus…) with a Disney copyright and Gyedo’s contact info. Also opens a blank window. I’ll see if I can make it do what I want.

From what I can tell, wxpython is allowed to be used in commercial releases:
“you may use, copy, link, modify and distribute under the user’s own terms, binary object code versions of works based on the Library.” I’ll have to figure out a tidy way to do this.

So I’m on a mac for now, and that mean one menu bar at the top of the screen.

This gives me a tk window, and adds a Tools menu like I want:

from Tkinter import *
root=Tk()
menubar = Menu(root)
 
toolsMenu=Menu(menubar)
toolsMenu.add_command(label="Some Tool")
menubar.add_cascade(label="Tools", menu=toolsMenu)
 
root.config(menu=menubar)

mainloop()

Now for panda:

from panda3d.core import loadPrcFileData
loadPrcFileData('', 'want-tk 1') # appears to not do anything

import direct.directbase.DirectStart
from direct.tkwidgets import AppShell
base.startTk() # appears to not do anything
shell= AppShell.AppShell()

run()

This gives 3 windows,
1: “Generic Application Frame” with “edit” and “help” popup menus at the top pretending to be like a menu bar or something
2: an empty tk window
3: a panda window (the only one I want)

It does not give me a reference to anything I can add menus to though. (I tried it on shell and got errors). Also, the run() call seems to block Tk from getting any time. If I use Tkinter directly, I can do menus, but I still get its blank window, and if I hide that window, the menus go away, and Tkinter does not get time to run at all. (My attempts at update tasks as below failed as well)

I tried adding this:

from direct.task import Task
def refreshApp(task):
    shell.update()
    return Task.cont
taskMgr.add(refreshApp, "refreshApp")

but it seems to have no effect.

And now for my slightly better luck with wx:

from direct.showbase.ShowBase import ShowBase
import direct.directbase.DirectStart
from direct.wxwidgets import WxAppShell
base.startWx()
base.setFrameRateMeter(True)

w=WxAppShell.WxAppShell
w.appname='X'
w.appversion='0.0'
w.copyright='Copyright 2010 Craig Macomber.\nAll Rights Reserved.'
w.contactname='Craig Macomber'
w.contactemail='X'

s=WxAppShell.WxAppShell()
#some yhings that exist: s.about, s.menuBar, s.menuFile, s.menuHelp

from wx import wx

menu = wx.Menu()
s.menuBar.Append(menu, "&Tools");

#base.taskMgr.remove("igLoop") # Makes everything freeze if uncommented

run()

This gives 2 windows, one empty one called “X” (or what ever I set my app name to I imagine), and a panda window. It also gives 2 help menus (one it makes, and the default system one that shows up after you click the menu bar. I think I can just delete the one panda makes on mac). I can add my own menus though, and wx seems to get the time it needs to work.

Currently, at least on mac, I can get menus that work with wx, if I ignore the extra help menu showing up, and the blank window that quits the app if you close it. I can’t make Tkinter and panda play together at all.

I haven’t gotten a good test in on windows yet (panda crashes on launch on my virtual windows box due to crappy graphics support, maybe I can make it work) and I did do a small wx test on linux, but the panda frame inside the wx window did not move when the window was moved, though I could probably fix that if I tried enough.

I’d rather avoid having larger and/or separate third party libraries, so if possible, I would either like to avoid wx, or discover a easy way to include it with my app. I think Tkinter comes with python, so it should be less of an issue.

So, how can I make Tkinter add menus to a panda application without spaying little empty windows around, and do so in a way where there is not a mainloop conflict? panda seems to have some built in stuff for doing this, but I can’t find any documentation about it at all (there is base.starttk/wx and want-tk/wx, there might be more, and I don’t even know what those things do.)

Also, in the long run, I’ll want to have multiple panda windows with menus. It would be good if what ever approach I end up won’t prohibit this, though it is not critical.

I don’t know if anyone has ever tried to use Tk with Mac. I think of Tk as kind of a dated technology; and we’d started to phase away from it long before we started the port of Panda to Mac.

That’s not to say that it can’t be used; it’s just that you’ll be the first to try it, and you might need to explore low-level operating system issues.

You should be able to run on Windows successfully with “load-display tinydisplay”; this runs in a software-only mode, and avoids the issues with hardware acceleration in a virtual display.

There are still some known issues with Mac and wx compatibility: in particular, parenting a Panda window to a wxPython window doesn’t work well on a Mac. (Mac OSX doesn’t really support the window-parenting concept in the same way that Windows and Linux do.)

David

Thanks for the suggestions David. I didn’t realize Tk was on its way out (another reason all this should probably have a manual page.) I guess I’ll push forward with wx then.

I don’t need window parenting for menus on mac though, so if I could just make that window that shows up invisible, I’d be fine.

As far as including wx in a distribution, I guess I can probably just cram the whole thing (40 mb compressed for mac, 160mb decompressed, ick!) in some folder and stick it on the path.

If you don’t need the Panda window, you can suppress it with “window-type none”. The p3d runtime system includes wxPython with “-r wx” on the packp3d command line.

David

I need the panda window, but not the wx window (on mac, menubars have nothing to do with the windows open). Thanks for the info about “-r wx”. It seems about half the time I try and figure out how to do something, the answer is panda already did it for me :slight_smile: