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

Posted

技术标签:

【中文标题】在 Python 中使用 Dock 的基本可可应用程序,但不是 Xcode 和所有附加功能【英文标题】:Basic cocoa application using dock in Python, but not Xcode and all that extras 【发布时间】:2009-10-04 20:46:22 【问题描述】:

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

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

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

以简单的方式定义停靠右键单击菜单的额外好处(例如:使用 Python 可调用列表)。

我是否可以不使用 Xcode 或 GUI 构建器而仅使用 Emacs 和 Python 来实现这一目标?

【问题讨论】:

您说的是 Cocoa 应用程序,但您真的只是指 Mac GUI 应用程序吗?如果是这样,你看过 py2app 了吗?您可以使用它来构建应用程序,其中包含 Python 中可用的大多数各种 UI,包括 PyObjC,并且有记录的方法可以创建自定义停靠图标。不过,不知道更新 Dock。 请注意,匿名应用也可以在登录时运行:您可以从“帐户系统偏好设置”窗格编辑登录项目列表。 @Ned - 是的,我的意思是一个 Mac GUI 应用程序(带有停靠图标和徽章)。我将更仔细地看一下 py2app。 (还将检查其他 UI 工具包是否提供更简单的 API 来与 Mac Dock 交互) 【参考方案1】:

安装最新的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.appopen dist 并将图标拖到 Dock 上,一切就绪(在您自己的机器上 - 由于 -A 标志,分发到其他机器可能无法正常工作,但没有它我无法构建,可能是由于错误安装的鸡蛋文件放在这台机器周围;-)。毫无疑问,您会想要自定义您的图标 &c。

这并不能满足您要求的“额外功劳”——它已经有很多代码了,我决定在这里停下来(额外功劳可能需要一个新问题)。另外,我不太确定我在这里执行的所有咒语是否真的必要或有用;根据您的需要,这些文档非常适合在没有 Xcode 的情况下制作 pyobjc .app,因此我从网上找到的示例代码的点点滴滴以及大量的试验和错误中将其组合在一起。不过,我希望它有所帮助!-)

【讨论】:

你会想用 pool.drain() 清空 schedule() 中创建的 NSAutoreleasePool。 @nail,调度永远不会结束,因为 scheduler.run 永远不会返回(因为每个滴答都会安排另一个),所以我认为在调用 scheduler.run 之后放置任何东西是没有意义的 - 认为应该在那里发表评论以澄清...? 再三考虑,我继续添加评论,因为它确实使程序更易于理解。 我不知道 sched 模块是如何工作的,但是根据你分配的 Cocoa 的内存管理规则,因此必须释放(即 NSAutoreleasePool 耗尽)。我会争论把它放在那里。如果 tick() 发生变化并且不再无限调度怎么办?这样可以避免被类似的东西烧毁。【参考方案2】:

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

【讨论】:

我当然知道 PyObjC。教程 developer.apple.com/cocoa/pyobjc.html 建议使用 Xcode 及其 GUI 构建器 .. 而我想要的只是一个无需额外工具即可在 Python 中使用的模块(就像 EasyDialogs 一样简单)。 @Sridhar:如果您查看我链接到的 PyObjC 站点,您会发现它根本不需要 Xcode。 文档假定需要 Xcode。 pyobjc.sourceforge.net/documentation/pyobjc-core/tutorial/… 另外请注意,我并不是在暗示“pyobjc 需要 xcode”,只是教程和文档是使用 Xcode 和 GUI 构建器编写的......而我想用独立的文本编写纯 Python -编辑器来创建一个带有停靠图标和菜单的简单应用程序。我希望你能理解我的问题的具体细节。 @Sridhar:它说您需要安装 Xcode 才能获得必要的支持工具。是的,如果你想构建一个界面,你确实需要使用 Interface Builder。但它并不要求您在任何时候都使用 Xcode。您可以在独立的文本编辑器中编写 Python 并创建一个带有停靠图标和菜单的简单应用程序。【参考方案3】:

Chuck 对 PyObjC 的看法是正确的。

然后你应该阅读这个 NSApplication 方法来改变你的图标。

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

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

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

【讨论】:

以上是关于在 Python 中使用 Dock 的基本可可应用程序,但不是 Xcode 和所有附加功能的主要内容,如果未能解决你的问题,请参考以下文章

如何在mac os X中获取正在运行的dock.app的pid_t

在可可应用程序中使用 xmpp 发送任何文件。是不是可以?

在多个应用程序中使用可可触摸框架项目

使用可可刷新finder中文件或文件夹的图标

在python中使用Mongodb

Mac OS X 可可应用程序中的 Internet 连接通知