python和Cocoa:关于statusbar scrip

2024-06-28 20:08:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在创建一个小脚本来检查我的gmail帐户中的邮件数量并将它们打印到 状态栏。函数gmail()返回新电子邮件的数量。我没有什么问题,但首先这是我迄今为止编写的代码(显然我是个新手):

class MyApplicationAppDelegate(NSObject):

var = 1

def applicationDidFinishLaunching_(self, sender):
    NSLog("Application did finish launching.")

    global ngmail

    self.statusItem = NSStatusBar.systemStatusBar().statusItemWithLength_(NSVariableStatusItemLength)

    while var == 1 :  
        ngmail2 = gmail();
        if  ngmail2 !=ngmail:
            self.statusItem.setTitle_("loading")
            self.statusItem.setTitle_(ngmail2)
            ngmail = ngmail2
        time.sleep(6)

1)为什么我需要线路“self.statusItem.setTitle_(“加载”)?如果没有那条线,它就不会自动更新。我真的不知道为什么。在

2)它正常运行,但每当我接近状态栏中的数字时,就会出现旋转轮子。
我想原因是因为我使用while,而应该使用nsrunloop之类的东西。有人能对此提出建议吗?在

3)如果我让我的mac进入睡眠状态并唤醒它,脚本将停止工作。有什么解决办法吗?也许这和上面的问题2)有关。在

谢谢!


Tags: 函数self数量电子邮件var邮件帐户gmail
1条回答
网友
1楼 · 发布于 2024-06-28 20:08:27

你所有的问题都是因为你阻塞了主线程。在

在Cocoa或几乎任何其他GUI框架中,主线程运行一个循环,该循环等待下一个事件,调用事件处理程序,并重复执行直到退出。在

事件处理程序applicationDidFinishLaunching_永远不会返回。这意味着可可永远无法处理下一个事件。最后,操作系统会注意到你没有反应,于是就提出了这个问题。在

有了Cocoa,有时候每次你给它一个机会,它都会潜入一些其他事件,比如在setTitle_调用时,即使你没有响应,操作系统也可以伪造一些东西,比如重新绘制窗口,所以你的应用程序不响应并不总是很明显。但这并不意味着你不需要解决问题。在

有很多方法可以做到这一点,但最简单的方法可能是使用后台线程。然后,ApplicationIDfinishLaunching_u可以启动后台线程,然后立即返回,从而允许主线程返回其作业处理事件。在

唯一棘手的是后台线程上运行的代码不能调用UI对象。那你怎么办?在

这就是^{}的作用。在


下面是一个例子:

class MyApplicationAppDelegate(NSObject):

    var = 1

    def background_work(self):
        global ngmail

        while var == 1 :  
            ngmail2 = gmail();
            if  ngmail2 !=ngmail:
                self.statusItem.setTitle_("loading")
                self.statusItem.performSelectorOnMainThread_withObject_waitUntilDone_('setTitle:', ngmail2, False)
            time.sleep(6)

    def applicationDidFinishLaunching_(self, sender):
        NSLog("Application did finish launching.")
        self.statusItem = NSStatusBar.systemStatusBar().statusItemWithLength_(NSVariableStatusItemLength)
        self.background_worker = threading.Thread(target=self.background_work)
        self.background_worker.start()    

唯一棘手的一点是必须使用ObjC名称作为选择器(setTitle:),而不是Python名称(setTitle_)。在


但是,您的代码有另一个细微的缺陷:var实际上没有同步,所以您可以在主线程中更改它的值,而后台线程却没有注意到。在

除此之外,执行sleep(6)意味着退出应用程序需要6秒钟,因为后台线程在完成睡眠之前不会到达检查var的代码。在

您可以使用Condition来修复这两个问题。在

^{pr2}$

(我假设您故意使用了var的class属性,而不是instance属性,因此我同样将condition设置为class属性,shutdown方法作为类方法。)

相关问题 更多 >