I've been putting together a couple of very simple Python utilities that require little or no UI but that I don't want to invoke via the command line, so I rummaged around in the PyObjC mailing-list archives for a while in search of a way to give them a Cocoa UI without going through the hassle of building .nib files and the like.
I eventually hit upon using the NSStatusBar class to add yet another little icon to the main menu bar, but since I could not find any decent samples that illustrated the whole thing (building the item, binding images and menus to it and making it highlight upon clicking upon), I decided to build a complete working sample and post it:
import objc, re, os from Foundation import * from AppKit import * from PyObjCTools import NibClassBuilder, AppHelper # poach one of the iSync internal images to get things rolling status_images = {'idle':'/Applications/iSync.app/Contents/Resources/English.lproj/iSyncHelp/gfx/iscic.png'} start_time = NSDate.date() class Timer(NSObject): images = {} statusbar = None state = 'idle' def applicationDidFinishLaunching_(self, notification): statusbar = NSStatusBar.systemStatusBar() # Create the statusbar item self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength) # Load all images for i in status_images.keys(): self.images[i] = NSImage.alloc().initByReferencingFile_(status_images[i]) # Set initial image self.statusitem.setImage_(self.images['idle']) # Let it highlight upon clicking self.statusitem.setHighlightMode_(1) # Set a tooltip self.statusitem.setToolTip_('Sync Trigger') # Build a very simple menu self.menu = NSMenu.alloc().init() # Sync event is bound to sync_ method menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Sync...', 'sync:', '') self.menu.addItem_(menuitem) # Default event menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'terminate:', '') self.menu.addItem_(menuitem) # Bind it to the status item self.statusitem.setMenu_(self.menu) # Get the timer going self.timer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_(start_time, 5.0, self, 'tick:', None, True) NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSDefaultRunLoopMode) self.timer.fire() def sync_(self, notification): print "sync" def tick_(self, notification): print self.state if __name__ == "__main__": app = NSApplication.sharedApplication() delegate = Timer.alloc().init() app.setDelegate_(delegate) AppHelper.runEventLoop()
The above code needs some minor tweaks, but it allows for multiple images, periodic updates, etc.