Search code examples
pythonwxpythonpyobjc

Getting pyobjc object from integer id


Is there a way to get a PyObjC proxy object for an Objective-C object, given only its id as an integer? Can it be done without an extension module?

In my case, I'm trying to get a Cocoa proxy object from the return value of wx.Frame.GetHandle (using wxMac with Cocoa).


Solution

  • The one solution I did find relies on ctypes to create an objc_object object from the id:

    import ctypes, objc
    _objc = ctypes.PyDLL(objc._objc.__file__)
    
    # PyObject *PyObjCObject_New(id objc_object, int flags, int retain)
    _objc.PyObjCObject_New.restype = ctypes.py_object
    _objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
    
    def objc_object(id):
        return _objc.PyObjCObject_New(id, 0, 1)
    

    An example of its use to print a wx.Frame:

    import wx
    
    class Frame(wx.Frame):
        def __init__(self, title):
            wx.Frame.__init__(self, None, title=title, pos=(150,150), size=(350,200))
    
            m_print = wx.Button(self, label="Print")
            m_print.Bind(wx.EVT_BUTTON, self.OnPrint)
    
        def OnPrint(self, event):
            topobj = objc_object(top.GetHandle())
            topobj.print_(None)
    
    app = wx.App()
    top = Frame(title="ObjC Test")
    top.Show()
    
    app.MainLoop()
    

    It's a little nasty since it uses ctypes. If there's a pyobjc API function I overlooked or some other neater way to do it, I'd surely be interested.