5

I am writing a wxPython application that remains open after closing all of its windows - so you can still drag & drop new files onto the OSX dock icon (I do this with myApp.SetExitOnFrameDelete(False)).

Unfortunately if I close all the windows, the OSX menubar will only contain a "Help" menu. I would like to add at least a File/Open menu item, or just keep the menubar of the main window. Is this somehow possible in wxPython?

In fact, I would be happy with a non-wxPython hack as well (for example, setting the menu in pyobjc, but running the rest of the GUI in wxPython). wxPython development in OSX is such a hack anyway ;)

UPDATE: I managed to solve this problem using the tip from Lyndsey Ferguson. Here's what I have done:

  • On startup I create a window which I show and hide immediately. I set its position to (-10000,-10000) so that it does not flicker on the screen (aargh, what a dirty hack!)
  • I create an empty EVT_CLOSE event handler in that window so that it cannot be closed.
  • It seems that destroying a window resets the OSX menu, but hiding does not... So when the last window is closed, I need to show and hide this window again (hiding is necessary so that the user cannot switch to this window using the Window menu or Cmd-`)

Yeah, this is really ugly... I will be very grateful if someone comes up with a prettier solution.

UPDATE 2: Actually it can be solved in a much easier way: if we do not close the last window, only hide it. And ensure that it does not respond to menu events anymore.

gyim
  • 8,803
  • 2
  • 19
  • 21
  • Yeah, it is an unpleasant hack - but it works and lets you focus on adding the features that you need :) – Lyndsey Ferguson Jun 03 '10 at 12:47
  • 1
    Interesting one. I used the hidden window hack once but set the coordinates to positive, beyond the screen's resolution (because either Windows or Linux did not handle well the negative ones). Bit me when a multi-monitor user complained that there was a dummy window on his second monitor :) – fraca7 Jun 03 '10 at 15:58

2 Answers2

2

Nowadays you can use wx.MenuBar.MacSetCommonMenuBar() to set the menu bar (which you have to create) that should be used when no windows are open.

If you just want a default macOS menu bar to be used (with the application and Window menus already there), this appears to be the minimal code:

menubar = wx.MenuBar()
wx.MenuBar.MacSetCommonMenuBar(menubar)

This will let your app respond to Command+Q out-of-the-box, too.

The wx.MenuItem IDs wx.ID_ABOUT and wx.ID_EXIT are special as menu items with those IDs are moved to the macOS Application menu. The docs actually refer to the application menu as the "Apple" menu (e.g. the menu described in the wx.MenuBar.OSXGetAppleMenu() function's docs is the application menu), possibly for historical reasons.

matatk
  • 761
  • 1
  • 6
  • 13
1

Can you create a hidden window that is offscreen somewhere? It is a hack, but I remember having to do a lot of hacks to make my wxPython-based application work correctly on Mac OS X.

Note:You'll have to disable the close button and set up that hidden window so that it doesn't show up in the Window menu.

Aside:Have you considered factoring out your GUI portion of your Python application and using PyObjC on Mac OS X? You'll get more native behaviours...

Lyndsey Ferguson
  • 5,306
  • 1
  • 29
  • 46
  • This is correct: the way wxWidgets works (or used to work) is that a menubar needed a frame to attach to (think Windows). Now, later versions of the wxWidgets framework (2.9, for example) might have fixed that issue, so you can associate a menu bar with the application... but I don't know if this is available up in wxPython land – RyanWilcox Jun 02 '10 at 23:03
  • Thanks for the tip! This hidden window is a good idea, although it needs some more hacking (see above)... And yeah, I plan to drop wxPython some time (it sucks on all platforms in a different way), but right now I don't have time to write the GUI twice. – gyim Jun 03 '10 at 07:17