【问题标题】:Growl Python binding with Click feedback?使用 Click 反馈咆哮 Python 绑定?
【发布时间】:2010-06-27 06:37:06
【问题描述】:

我正在尝试使用 Growl Python 绑定(来自 Growl 存储库的 Growl.py v0.7)来编写一个小型应用程序。当前缺少的功能之一是发送到 Python 的点击通知。

我知道在 Objective-C 中,当用户点击通知时,它会向正在运行的应用程序发送一个触发器。我想对 Python 绑定做类似的事情。当用户点击通知时,我想让 Python 程序在浏览器中打开一个 URL(或以其他方式处理事件)。

对我如何实现它有什么想法吗?

更新:感谢 synthesizerpatel,他提供了一个很有前途的解决方案,我相信他的话对 Lion 有效。不幸的是,我开始从 Mac 中淡出,所以我不再做太多的 Mac 编程了。不过,我做了一些调试,因为它仍然无法在 Snow Leopard 上运行,原因如下:

Discussion Growl PyObjC not working with PyObjC 2.2b3

Source code

【问题讨论】:

  • 运气好吗?我也很想知道。
  • 您是在寻找这个来捕获所有咆哮通知,还是只是一个能够发送咆哮通知并能够在用户关闭鼠标点击时捕获鼠标点击的 Python 应用程序?跨度>
  • 主要是python应用。
  • 对于它的价值(对于其他可能对此问题/解决方案感兴趣的人,Lion 的 objc.__version__ 报告 2.3.2a0。也许可以构建 objc 的东西来自他们的 SVN for Snow Leopard。但是,简而言之,objc 模块是一个好主意,但据我所知,它只是缺乏一个充满活力的开发社区。我很高兴它在 Lion 上工作,但如果你查看他们的源代码随着时间的推移,您可以看到有多少示例已被删除,因为它们在某个时候停止工作并且没有人费心去修复它们。caveat pyobjc
  • 是的,我可能可以重新编译 pyobjc,它可以在我的机器上运行。但是,要求每个最终用户重新安装 pyobjc 以仅使用我的应用程序是不可行的。因此,应该采取另一种方法......我确实喜欢 pyobjc 的想法,但是

标签: python macos pyobjc growl


【解决方案1】:

这是你想要的吗?

#!/usr/bin/env python 
#
# pyGrr!
#
# This code was originally found @
# http://www.cocoaforge.com/viewtopic.php?f=6&t=13359&p=91992&hilit=pyobjc+growl
# It is (to the best of our knowledge) the work of user 'tooru' on the same
# website.
#
# I make no claim to this code, all I did was get it working with PyObjC on Lion
# reformatted it a bit and added some more verbose explanations of what the script
# does. To be honest, I haven't touched pyobjc in a couple years and I was amazed
# that it still works! Even more amazed that I was able to get this example working
# in about 20 minutes.
#
# Great job tooru! 
# 
#   I have verified this code works with the following combination of 
#   packages / versions
#
#   * OSX Lion 10.7.3
#   * Python 2.7
#   * Growl 1.3
#   * Growl SDK 1.3.1
#
# 
# - Nathan Ramella nar@hush.com (http://www.remix.net)
##################################################################################

import objc
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper
import time
import sys
import os

myGrowlBundle = objc.loadBundle(
  "GrowlApplicationBridge",
  globals(),
  bundle_path = objc.pathForFramework(
    '/Library/Frameworks/Growl.framework'
  )
)

class MenuMakerDelegate(NSObject):

  """
  This is a delegate for Growl, a required element of using the Growl
  service.

  There isn't a requirement that delegates actually 'do' anything, but
  in this case, it does. We'll make a little menu up on the status bar
  which will be named 'pyGrr!'

  Inside the menu will be two options, 'Send a Grr!', and 'Quit'. 

  Send a Grr! will emit a growl notification that when clicked calls back
  to the Python code so you can take some sort of action - if you're that
  type of person.
  """

  statusbar = None
  state = 'idle'

  def applicationDidFinishLaunching_(self, notification):

    """
    Setup the menu and our menu items. Getting excited yet?
    """

    statusbar = NSStatusBar.systemStatusBar()
    # Create the statusbar item
    self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)

    self.statusitem.setHighlightMode_(1)  # Let it highlight upon clicking
    self.statusitem.setToolTip_('pyGrr!')   # Set a tooltip
    self.statusitem.setTitle_('pyGrr!')   # Set an initial title

    # Build a very simple menu
    self.menu = NSMenu.alloc().init()
    menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
      'Send a Grr!',
      'rcNotification:',
      ''
    )
    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)

  def rcNotification_(self,notification):

    """
    This is run when you select the 'Send a Grr!' menu item. It 
    will lovingly bundle up a Grr and send it Growl's way.
    """

    print "Sending a growl notification at", time.time()

    GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(
      "Grr! - I'm a title!",
      "This is where you put notification information.",
      "test1",
      None,
      0,
      False,
      "this ends up being the argument to your context callback"
    )

class rcGrowl(NSObject):

  """
  rcGrowl registers us with Growl to send out Grrs on behalf
  of the user and do 'something' with the results when a 
  Grr has been clicked.

  For additional information on what the what is going on
  please refer to the growl dox @ 

  http://growl.info/documentation/developer/implementing-growl.php
  """

  def rcSetDelegate(self):
    GrowlApplicationBridge.setGrowlDelegate_(self)

  def registrationDictionaryForGrowl(self):

    """
    http://growl.info/documentation/developer/implementing-growl.php#registration
    """

    return {
      u'ApplicationName'    :   'rcGrowlMacTidy',
      u'AllNotifications'   :   ['test1'],
      u'DefaultNotifications' :   ['test1'],
      u'NotificationIcon'   :   None,
    } 

  # don't know if it is working or not
  def applicationNameForGrowl(self):
    """ 
    Identifies the application.
    """
    return 'rcGrowlMacTidy'

  #def applicationIconDataForGrowl(self):
    """
    If you wish to include a custom icon with the Grr,
    you can do so here. Disabled by default since I didn't
    want to bloat up this up
    """
    #icon = NSImage.alloc().init()
    #icon = icon.initWithContentsOfFile_(u'remix_icon.tiff')
    #return icon

  def growlNotificationWasClicked_(self, ctx):

    """
    callback for onClick event
    """
    print "we got a click! " + str(time.time()) + " >>> " + str(ctx) + " <<<\n"

  def growlNotificationTimedOut_(self, ctx):

    """ 
    callback for timing out
    """
    print "We timed out" + str(ctx) + "\n"

  def growlIsReady(self):

    """
    Informs the delegate that GrowlHelperApp was launched
    successfully. Presumably if it's already running it
    won't need to run it again?
    """
    print "growl IS READY"


if __name__ == "__main__":

  # Both 'growlnotify' and this script seem to have the following
  # error after emitting a Grr!
  #
  # Error Domain=GCDAsyncSocketErrorDomain Code=4 "Read operation timed out" 
  # UserInfo=0x7fa444e00070 {NSLocalizedDescription=Read operation timed out}
  # 
  # So, we redirect stderr to /dev/null so that it doesn't muck up
  # the output of this script. Some folks say upgrading Growl fixes it,
  # others still have the problem. Doesn't seem to make much of a difference
  # one way or another, things still seem to work regardless.

  fp = os.open('/dev/null', os.O_RDWR|os.O_CREAT, 0o666)
  dupped = os.dup(2)
  os.dup2(fp, 2)

  # set up system statusbar GUI
  app = NSApplication.sharedApplication()
  delegate = MenuMakerDelegate.alloc().init()
  app.setDelegate_( delegate )

  # set up growl delegate
  rcGrowlDelegate=rcGrowl.new()
  rcGrowlDelegate.rcSetDelegate()
  AppHelper.runEventLoop()

【讨论】:

  • 您好,感谢您的脚本。不幸的是,它对我不起作用,因为我有雪豹咆哮 1.2.2
  • 如果有的话,在这种情况下你应该有更少的问题。 :D 但是,事实上,这正是您正在寻找的。我很想知道您收到了哪些错误消息。
  • 是的,我应该提供更多细节...该脚本听起来确实如我所愿。在我运行程序后,它创建了带有两个选项的状态菜单。虽然,在我点击“发送 Grr!”后,我只在控制台中收到一条消息,“在 ... 发送咆哮通知”而没有实际的咆哮通知。
  • 换句话说,Growl 通知从未出现过,我检查了系统首选项 pyGrr!应用程序似乎也没有注册。我想知道从 1.2.2 -> 1.3 是否有 API 变化
  • 我想我知道发生了什么 - 在 'if name == 'main' 之后,删除重定向的 3 行代码标准错误到 /dev/null。您可能会收到更好的错误消息。看起来 1.2.1 和 1.3 之间的 API 发生了变化。而且由于我只有 Lion,所以我无法真正给你任何见解。无论如何,您应该已经升级到 Lion。 :D
猜你喜欢
  • 2014-10-19
  • 2012-06-12
  • 2011-09-26
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多