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!
They are indeed, thank you. I assume you have to configure soft tabs as well, or do the templates take care of that?
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.
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.
Nope. It’s pretty painful to do a lot of Python coding in Xcode’s editor.
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.
감사합니다 ㅜㅜ 하나님 부처님.
Thank~~~~~s a lot ><///
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
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.
Well done!!!
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.
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.
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).
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.
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.
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
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
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.
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
Each MacTech back-issue is $10. Can you recommend a good month?
J
The series I’m doing on Cocoa-Python started in Jan 2013 and will probably wrap up in May 2013.
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()
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
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.
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
This is not Xcode specific, but in any OS X file open dialog, type a slash to get a field in which to type (or paste) a path.
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.
Should I download an earlier version of Xcode. If so where do I download, and what version should I get.
The framework is in the 10.8 SDK. See: http://stackoverflow.com/questions/19555395/python-framework-is-missing-from-os-x-10-9-sdk-why-also-workaround
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
If you are using Xcode 5, use these templates instead: https://github.com/gregneagle/Xcode5CocoaPythonTemplates