Xcode 4 Cocoa-Python Templates

Update 30 April 2014: If you are using Xcode 5, please use these templates instead: https://github.com/gregneagle/Xcode5CocoaPythonTemplates

I’ve developed a few applications using PyObjC — a bridge between Python and Apple’s Objective-C frameworks. Using Xcode 3 and some file and project templates, it was possible to use Interface Builder to create your user interface, and use Python and the PyObjC bridge to write the logic of your application.

With the release of Xcode 4, it seemed that PyObjC (or Cocoa-Python) development was not supported. Several discussions on the internet seemed to indicate that the Xcode-Interface Builder integration with Python was missing from Xcode 4, so I stayed away from Xcode 4.

With the move to Lion, avoiding Xcode 4 was no longer an option. I opened one of my PyObjC projects in Xcode 4.3, and found that Xcode/Interface Builder integration worked as I expected — I could bind UI objects to Python code as expected. So working on existing projects using Xcode 4.3 seemed to be no problem.

But starting a new PyObjC project was difficult. Xcode 3 had some project templates for creating “Cocoa-Python” applications and file templates for Python subclasses of certain NSObjects. Later versions of Xcode 3 did not include these templates, but you could download them and install them yourself. See http://ioanna.me/2009/09/installing-pyobjc-xcode-templates-in-snow-leopard/ for details.

Xcode 4 changed the format of file and project templates, and the downloadable Cocoa-Python templates for Xcode 3 do not work with Xcode 4. I looked around for updated templates, but didn’t find any online. So I decided to try to make my own…

The result is available here: https://github.com/gregneagle/Xcode4CocoaPythonTemplates

Hope these are useful to someone else!

Advertisement
Xcode 4 Cocoa-Python Templates

30 thoughts on “Xcode 4 Cocoa-Python Templates

  1. I don’t think templates can configure things like that. Xcode 4 is a noticibly worse editor for Python and Cocoa-Python. It fights proper indentation. I think Xcode 3 did a better job of code completion for PyObjC-versions of Cocoa method calls, but that could be me misremembering.

    1. jgavris13 says:

      have you found a workaround to xcode’s fighting of indentation? i love writing cocoa in xcode, but i am stuck with textmate because it actually understands my python coding style.

    2. jgavris13 says:

      i just fired up xcode 3, compared indentation settings, they are the same as i have them in xcode 4. new lines begin at the beginning of the previous line, instead of at the end, which is exactly what i want for python. xcode 3 also had xclangspec’s, which means i had ruby syntax coloring, too. hopefully xcode 4 opens up more plugin and configuration interfaces for us hackers.

  2. Sir, Thank you for your article.
    but when I Try this template,
    it crashes when execute PyRun_SimpleFile function in main.m.
    what can i do fix it?

    Environments:
    OSX Lion 10.7.3
    XCODE 4.3.2
    Python 2.7.2

  3. I cannot reproduce your issue. Can you describe exactly what you did?

    I create a new project using the Cocoa-Python Application template, then click the Run button. I get a running application with a single empty window.

    OS X 10.7.3
    Xcode 4.3.2
    Python 2.7.1

    The fact that you are running Python 2.7.2 may be the issue — did you install your own Python? If so, you may not have the PyObjC Cocoa bindings available.

  4. Peter says:

    Thank you for doing this. I installed the templates (after creating the ~/Library/Developer/Xcode/Templates directory) and am now able to create new Cocoa-python projects. Should Interface Builder work? I am trying to create new actions and outlets for buttons and text boxes but can’t seem to get it to work. I am not sure if Interface Builder doesn’t work for PyObjC currently or whether I am not doing something properly.

    1. Interface Builder works for me; make sure you are using

      foo = IBOutlet()

      and

      @IBAction
      def someAction_(self, sender)

      decorators/hints so that Xcode/IB knows which variables are your outlets and which methods are actions. These aren’t new; you needed to use these with PyObjC and prior versions of Xcode as well.

      1. Peter says:

        Thanks for the reply. I got IB to recognize the IBOutlets but I can’t get it to recognize IBActions so I have no way to connect buttons to python functions (e.g. someAction_ even when preceded by the @IBAction decorator).

  5. Here’s an action inside an NSWindowController object that works for me:

    @IBAction
    def cancelBtnClicked_(self, sender):
    NSApp.terminate_(self)

    I control-drag from the cancel button to the Window Controller object, and then can pick an available action.

  6. Jerry LeCarpentier says:

    Hi Greg.

    Thank you so much for this. Can you help me to understand how to hook this up? I’ve created the simplest project called PlainJanePyObjCTest.xcodeproj using your template. I added a Python NSDocument Subclass file called mainControllers.py containing all of the goodies your template provides + the single def:

    @IBAction
    def cancelBtnClicked_(self, sender):
    NSApp.terminate_(self)

    which falls under class mainControllers(NSDocument):

    I added “import mainControllers” to main.py, then I created a “Quit” button in the only window in MainMenu.xib. I then selected “File’s Owner” and with the Identity Inspector filled in the “Custom Class” as “mainControllers.”

    This allowed me to control-click connect the “Quit” button to Received Actions -> cancelBtnClicked.

    Finally, I clicked command-R to run. The “Build” was fine. However, I then got the error message:

    2013-04-20 21:56:09.586 PlainJanePyObjCTest[49408:403] Could not connect the action cancelBtnClicked: to target of class NSApplication

    Of course, then the “Quit” button was non-functional.

    I have no idea where to go from here. I’d appreciate any insight you can provide. I’m running OS 10.7.5, Xcode 4.6, Python 2.7, PyObjC 2.5.1.

    Thanks much.

    Jerry LeC.

  7. Jerry LeCarpentier says:

    Duh…

    I got it! Using the Object Library, I created a mainControllers *object * in the little Objects panel under AppDelegate, then control connected it there. It worked! This will certainly open up some very cool possibilities. Thanks for the templates!

    JLeC

  8. Jerry LeCarpentier says:

    One last thing. Where does my SimpleExample.app end up? Something is obviously running, by there apparently is no app produced. Or is this an Xcode setting?

    I had thought that using Xcode eliminated the need to use py2app.

    Thanks for any tips.

    JLeC

  9. Control-click on the running’s application’s icon in the Dock and choose Options->Show in Finder to see where Xcode builds it.

    There is no need to use py2app if you are building apps using Cocoa-Python with Xcode.

    You might be interested in a series of articles I am doing for MacTech magazine on using Cocoa-Python to build Mac applications. The articles started in the Jan 2013 issue and are available as single-issues via the iPad MacTech Newstand app.

    You might be able to order back issues directly from MacTech if you don’t have an iPad.

    1. Jerry LeCarpentier says:

      Thanks for the tip! I didn’t think of that. It’s 4 levels down from ~/Library/Developer/Xcode/DerivedData/ in some cryptically named directory tree. Is there any way to specify this?

      Yes, I’d be interested in the articles. I don’t have and iPad, but will investigate. Thanks again.

      J

  10. Jerry LeCarpentier says:

    So after importing the appropriate libraries, I managed to get everything below to work. With the interface builder, I created a window with an increment button, decrement button, a “count” text box, a plot button, and a quit button, and an NSImageView. The buttons are wired up in the obvious way.

    I need to thank StreyLab and Scott Robertson for the StringIO trick and buildNSImage:

    http://streylab.com/blog/2012/11/22/matplotlib-running-in-cocoa-under-xcode.html

    http://classic.scottr.org/blog/2008/dec/25/building-cocoa-guis-python-pyobjc-part-six/

    Anyway, when I hit the “plot” button, the main “drawplot” function is called, and everything works. It’s not even slow. My question is: Is there a better way to more directly render the matplotlib output into an NSImageView? Also, is there a recommended way to detect mouseup (and mouse position) when on an NSImageView? And then relate that to real coordinates?

    Thanks for any tips.

    Jerry LeC

    =======

    class SimpleXibDemoController(NSWindowController):

    count = 1
    counterTextField = objc.IBOutlet()
    time = arange(0, 1, 0.002)
    imageDisplay = objc.IBOutlet()

    def windowDidLoad(self):
    NSWindowController.windowDidLoad(self)

    @objc.IBAction
    def increment_(self, sender):
    self.count += 1
    print(“Incrementing…”)
    self.updateDisplay()

    @objc.IBAction
    def decrement_(self, sender):
    if (self.count > 1):
    self.count -= 1
    print(“Decrementing…”)
    self.updateDisplay()

    @objc.IBAction
    def drawplot_(self, sender):
    freq = self.count
    f=StringIO.StringIO()
    plt.figure()
    y=np.sin(2*pi*freq*self.time)
    plt.plot(self.time, y)
    plt.savefig(f,format=’png’)
    out=f.getvalue()
    print(“Plotting…”)
    self.ImageOut=self.buildNSImage(out)
    f.close()
    self.updateDisplay()

    def updateDisplay(self):
    self.counterTextField.setStringValue_(self.count)
    self.imageDisplay.setImage_(self.ImageOut)

    def buildNSImage(self, bytes):
    data = NSData.dataWithBytes_length_(bytes, len(bytes))
    return NSImage.alloc().initWithData_(data)

    if __name__ == “__main__”:
    app = NSApplication.sharedApplication()

    # Initiate the contrller with a XIB
    viewController = SimpleXibDemoController.alloc().initWithWindowNibName_(“MainMenu”)

    # Show the window
    viewController.showWindow_(viewController)

    # Bring app to top
    NSApp.activateIgnoringOtherApps_(True)

    from PyObjCTools import AppHelper
    AppHelper.runEventLoop()

  11. Phil Sanders says:

    These templates are great. I’m new to programming and I wanted to find a way to create an OS app using only python (or pyobjc once I learned of it).

    I am experiencing a problem however. When I try to build the product, it says “Build Failed”. I get a “Lexical or Preprocessor issue” that says ‘Python/Python.h’ file not found and highlights line 11 in the ‘main.m’ file (#import ).

    I apologize if this post is too wordy, I just wanted to communicate clearly. Any help is appreciated

  12. Sounds like you are using Xcode 5 instead of the Xcode 4 these template were built for two years ago.

    These templates will work with Xcode 5, but Xcode 5 does not automatically/correctly add the Python framework to your project using these templates.

    You can manually fix this.

    After creating a new Cocoa-Python project under Xcode 5, if you look under the Frameworks group folder in the left sidebar file view, you’ll see that “Python.framework” is in red, indicating that Xcode can’t find it.

    Click on “Python.framework”, then select the menu View->Utilities->Show File Inspector.

    To the right, you’ll see some information about where it thinks the Python.framework can be found. Click the Location pop-up menu, and change its value to “Relative to SDK”. Then click the little gray folder icon immediately below and navigate to and select /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/Python.framework (or /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Python.framework if you are using the 10.8 SDK)

    The Python framework should now look “normal” in the source view and you should be able to build your project.

    I’ll probably write a proper blog post about this. I should also look into possibly updating the templates so this manual stuff isn’t needed.

  13. Phil Sanders says:

    Thankyou very much. One minor thing though. I’m not sure how to navigate to the location that you mentioned. After clicking the gray folder, I can get to the Xcode application, but no further. I right clicked on it to try to find the package contents, but the only option was Quick Look. I’m not sure how to type in a file path from that window either. Also I went into Finder to view the file, and I can’t find it.

    I’m new to Xcode so I may be missing something obvious. Once again thank you for any help

      1. Phil Sanders says:

        That works, and I was able to copy and paste the path that you mentioned. The file wasn’t there though. There was an alphabetized list of .framework files, but python was not one of them.

  14. Phil Sanders says:

    Should I download an earlier version of Xcode. If so where do I download, and what version should I get.

  15. Jerry LeCarpentier says:

    Hi all. I’m revisiting here as I’m not finding anywhere on line to go after *extensive* search. Since my last post, I upgraded computers and my OS to Mavericks. I’m having a hard time finding my way through the maze of what still works and what doesn’t in my Python space.

    I appear to now be running Xcode 5. Ugh…

    So, I’m thinking of abandoning ship and doing a few things in Tkinter built for Cocoa. This has become a bit of a trial as well. My Python version 2.7.6 (anaconda) always launches Quartz instead of Cocoa tk.

    At one point I had some tk Cocoa stuff running, but it is old and I can’t find it anyway. Deconstructing and reconstructing things has become problematic.

    Any thoughts would be appreciated.

    JLeC

Comments are closed.