misha misha - 5 months ago 38
Python Question

Unable to focus on widgets in OS/X

I'm running Python 2.7.5 with wxWidgets installed through homebrew.

My issue is that keyboard events aren't picked up at all when running on OS/X. Consider the following sample source:


import wx
import wx.xrc
class MyFrame2 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.m_button1 = wx.Button( self, wx.ID_ANY, u"MyButton", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.m_button1, 0, wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.Centre( wx.BOTH )
# Connect Events
self.m_button1.Bind( wx.EVT_BUTTON, self.OnClick )
def __del__( self ):
# Virtual event handlers, overide them in your derived class
def OnClick( self, event ):


from noname import MyFrame2
class MyFrame2Impl(MyFrame2):
def __init__(self, parent):
MyFrame2.__init__(self, parent)
def OnClick(self, event):
self.m_button1.SetLabel(str(wx.Window.FindFocus() != None))

import wx
app = wx.App(False) # Create a new app, don't redirect stdout/stderr to a window.
frame = MyFrame2Impl(None) # A Frame is a top-level window.
frame.Show(True) # Show the frame.

On Ubuntu, once I click the button, it shows "True". Pressing spacebar clicks the button. On OS/X, once I click the button, it shows "False". Pressing spacebar achieves nothing.

At the bottom of the WxMac FAQ (http://www.wxwidgets.org/docs/faqmac.htm) it says this:

Why can't I set focus to my wxMac application? Because you didn't
build your application as a bundle. You must create a bundle for Mac
OS X applications, simply running the usual g++
wx-config --cxxflags
-o minimal minimal.cpp is not enough to build a correctly working Mac application. Please look at the samples makefiles which do
build bundles under Mac OS X or read this wiki topic for more details.

I've made a bundle using this script:

from setuptools import setup
APP = ["main.py"]
OPTIONS = {"argv_emulation": True, "includes": ["wx"]}
setup(app=APP, options={"py2app": OPTIONS}, setup_requires=["py2app"])

which I use to build a bundle with the command:

python setup.py py2app

This makes an executable, but the focus problem still persists. As a consequence, I'm unable to use the keyboard to control the application. How can I get the application to detect keyboard events?

Answer Source

I ended up coding around the problem.

Previously, my application was handling keyboard events globally (see http://wiki.wxwidgets.org/Catching_key_events_globally).

I couldn't get this to work on OS/X, so I gave up and rewrote the application such that it captures keyboard events locally. More specifically, the application includes a menu bar, and that menu bar has items. I can handle keyboard events by assigning keyboard shortcuts to the menu bar items.

I'm not sure why global handling doesn't work on OS/X, but I don't really care anymore.