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

发布于 2024-08-06 04:07:52 字数 514 浏览 5 评论 0原文

看来,如果我想创建一个带有停靠图标等的非常基本的 Cocoa 应用程序,我会 必须使用 Xcode 和GUI 构建器(带有PyObjC)。

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

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

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

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

It seems that if I want to create a very basic Cocoa application with a dock icon and the like, I would have to use Xcode and the GUI builder (w/ PyObjC).

The application I am intending to write is largely concerned with algorithms and basic IO - and thus, not mostly related to Apple specific stuff.

Basically the application is supposed to run periodically (say, every 3 minutes) .. pull some information via AppleScript and write HTML files to a particular directory. I would like to add a Dock icon for this application .. mainly to showing the "status" of the process (for example, if there is an error .. the dock icon would have a red flag on it). Another advantage of the dock icon is that I can make it run on startup.

Additional bonus for defining the dock right-click menu in a simple way (eg: using Python lists of callables).

Can I achieve this without using Xcode or GUI builders but simply using Emacs and Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

说谎友 2024-08-13 04:07:52

安装最新的 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打开 dist 并将图标拖到 Dock 上,一切就绪(在您自己的计算机上 - 由于 -A 标志,分发到其他计算机可能不起作用,但如果没有它,我在构建时遇到了麻烦,可能是由于这台机器周围放置了错误安装的 Egg 文件;-)。毫无疑问,您会想要自定义您的图标。

这并不能满足您要求的“额外学分”的要求——它已经有很多代码了,我决定在这里停下来(额外的学分可能需要提出一个新问题)。另外,我不太确定我在这里执行的所有咒语实际上是必要的还是有用的;根据您的需要,文档对于在没有 Xcode 的情况下制作 pyobjc .app 是相当困难的,所以我从网上找到的一些示例代码加上大量的试验和错误将其拼凑在一起。不过,我希望它能有所帮助!-)

Install the latest py2app, then make a new directory -- cd to it -- in it make a HelloWorld.py file such as:

# 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()

Of course, in your real code, you'll be performing your own periodic actions every 3 minutes (rather than writing a temp file every 20 seconds as I'm doing here), doing your own status updates (rather than just showing a counter of the number of files written so far), etc, etc, but I hope this example shows you a viable starting point.

Then in Terminal.App cd to the directory containing this source file, py2applet --make-setup HelloWorld.py, python setup.py py2app -A -p PyObjC.

You now have in subdirectory dist a directory HelloWorld.app; open dist and drag the icon to the Dock, and you're all set (on your own machine -- distributing to other machines may not work due to the -A flag, but I had trouble building without it, probably due to mis-installed egg files laying around this machine;-). No doubt you'll want to customize your icon &c.

This doesn't do the "extra credit" thingy you asked for -- it's already a lot of code and I decided to stop here (the extra credit thingy may warrant a new question). Also, I'm not quite sure that all the incantations I'm performing here are actually necessary or useful; the docs are pretty latitant for making a pyobjc .app without Xcode, as you require, so I hacked this together from bits and pieces of example code found on the net plus a substantial amount of trial and error. Still, I hope it helps!-)

℡寂寞咖啡 2024-08-13 04:07:52

Mac OS X 10.5 和 10.6 中附带的 PyObjC 非常接近您正在寻找的内容。

PyObjC, which is included with Mac OS X 10.5 and 10.6, is pretty close to what you're looking for.

独守阴晴ぅ圆缺 2024-08-13 04:07:52

Chuck 关于 PyObjC 的看法是正确的。

然后,您应该阅读有关此 NSApplication 方法来更改图标的信息。

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

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

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

Chuck is correct about PyObjC.

You should then read about this NSApplication method to change your icon.

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

For the dock menu, implement the following in an application delegate. You can build an NSMenu programmatically to avoid using InterfaceBuilder.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文