在Python中使用dock的基本cocoa应用程序,但不是Xcode和所有附加功能

时间:2009-10-04 20:46:23

标签: python cocoa pyobjc dock

似乎如果我想创建一个带有停靠图标等的非常基本的Cocoa应用程序,我会have to use Xcode和GUI构建器(w / PyObjC )。< / p>

我打算编写的应用程序主要关注算法和基本IO - 因此,并不主要与Apple特定的东西相关。

基本上应用程序应定期运行(例如,每3分钟一次)..通过AppleScript提取一些信息并将HTML文件写入特定目录。我想为这个应用程序添加一个Dock图标..主要是为了显示进程的“状态”(例如,如果有错误......停靠图标上会有一个红色标记)。 dock图标的另一个优点是我可以在启动时运行它。

以简单的方式定义Dock右键菜单的额外奖励(例如:使用Python的callables列表)。

我可以在不使用Xcode或GUI构建器但只使用Emacs和Python的情况下实现这一目标吗?

3 个答案:

答案 0 :(得分:8)

安装最新的py2app,然后创建一个新目录 - cd到它 - 在其中创建一个HelloWorld.py文件,例如:

# generic Python imports
import datetime
import os
import sched
import sys
import tempfile
import threading
import time

# need PyObjC on sys.path...:
for d in sys.path:
  if 'Extras' in d:
    sys.path.append(d + '/PyObjC')
    break

# objc-related imports
import objc
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper

# all stuff related to the repeating-action
thesched = sched.scheduler(time.time, time.sleep)

def tick(n, writer):
  writer(n)
  thesched.enter(20.0, 10, tick, (n+1, writer))
  fd, name = tempfile.mkstemp('.txt', 'hello', '/tmp');
  print 'writing %r' % name
  f = os.fdopen(fd, 'w')
  f.write(datetime.datetime.now().isoformat())
  f.write('\n')
  f.close()

def schedule(writer):
  pool = NSAutoreleasePool.alloc().init()
  thesched.enter(0.0, 10, tick, (1, writer))
  thesched.run()
  # normally you'd want pool.drain() here, but since this function never
  # ends until end of program (thesched.run never returns since each tick
  # schedules a new one) that pool.drain would never execute here;-).

# objc-related stuff
class TheDelegate(NSObject):

  statusbar = None
  state = 'idle'

  def applicationDidFinishLaunching_(self, notification):
    statusbar = NSStatusBar.systemStatusBar()
    self.statusitem = statusbar.statusItemWithLength_(
        NSVariableStatusItemLength)
    self.statusitem.setHighlightMode_(1)
    self.statusitem.setToolTip_('Example')
    self.statusitem.setTitle_('Example')

    self.menu = NSMenu.alloc().init()
    menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
        'Quit', 'terminate:', '')
    self.menu.addItem_(menuitem)
    self.statusitem.setMenu_(self.menu)

  def writer(self, s):
    self.badge.setBadgeLabel_(str(s))


if __name__ == "__main__":
  # prepare and set our delegate
  app = NSApplication.sharedApplication()
  delegate = TheDelegate.alloc().init()
  app.setDelegate_(delegate)
  delegate.badge = app.dockTile()
  delegate.writer(0)

  # on a separate thread, run the scheduler
  t = threading.Thread(target=schedule, args=(delegate.writer,))
  t.setDaemon(1)
  t.start()

  # let her rip!-)
  AppHelper.runEventLoop()

当然,在您的真实代码中,您将每3分钟执行一次自己的定期操作(而不是每隔20秒写一个临时文件,就像我在这里做的那样),进行自己的状态更新(而不仅仅是显示到目前为止所写文件数量的计数器等等,但我希望这个例子向您展示一个可行的起点。

然后在Terminal.App中cd到包含此源文件的目录py2applet --make-setup HelloWorld.pypython setup.py py2app -A -p PyObjC

您现在在子目录dist中有一个目录HelloWorld.app; open dist并将图标拖到Dock上,并且你已全部设置(在你自己的机器上 - 由于-A标志,分发到其他机器可能无法正常工作,但是如果没有它我就无法建立,可能是由于错误安装的鸡蛋文件放在这台机器周围;-)。毫无疑问,您需要自定义图标&amp; c。

这不是你要求的“额外信用” - 这已经是很多代码了,我决定停在这里(额外的信用可能需要一个新的问题)。另外,我不太确定所有我在这里执行的咒语实际上是必要的还是有用的;如果你需要的话,文档非常适合制作一个没有Xcode的pyobjc .app,所以我在网上找到了一些代码和部分示例代码,加上大量的反复试验。不过,我希望它有所帮助! - )

答案 1 :(得分:2)

PyObjC,包含在Mac OS X 10.5和10.6中,非常接近您所需的内容。

答案 2 :(得分:0)

Chuck对PyObjC是正确的。

然后,您应该阅读有关此NSApplication方法的内容以更改您的图标。

-(void)setApplicationIconImage:(NSImage *)anImage;

对于停靠菜单,请在应用程序委托中实现以下内容。您可以通过编程方式构建NSMenu以避免使用InterfaceBuilder。

-(NSMenu *)applicationDockMenu:(NSApplication *)sender;