每秒更新GTK + MenuItem倒计时和周期函数调用

时间:2013-02-20 15:13:18

标签: python gtk

这是我的国际空间站指标。我正在尝试创建一个显示倒计时的GTK MenuItem。这将使用AppIndicator3在Ubuntu Unity指标中。我希望这个MenuItem(futpass)每秒刷新一次(即倒计时实时显示),但也希望它在未选择菜单时保持不活动状态,以免消耗系统资源。问题是,我无法让它自己刷新。

因为每次需要运行checkiss之间需要很长的等待时间,所以我还需要知道在设定的时间以最少的CPU唤醒来调用此函数的正确方法。

到目前为止,这是我的(粗略)代码:

#!/usr/bin/env python
#print time.localtime( time.time() )
import json, urllib2, time, math

#indicator
from gi.repository import Gtk
from gi.repository import AppIndicator3 as appindicator
class indicator():
    def __init__(self):
        #create indicator
        self.ind = appindicator.Indicator.new (
                        "issindicator",
                        "indicator-messages",
                        #"indicator-messages",
                        appindicator.IndicatorCategory.APPLICATION_STATUS)
        self.ind.set_status (appindicator.IndicatorStatus.ACTIVE)

        self.ind.set_attention_icon ("indicator-messages-new")

        #dropdown menu
        #now items
        self.menu = Gtk.Menu()
        self.curpass = Gtk.MenuItem("not refreshed")
        self.curpass.connect("activate", self.checkiss)
        self.menu.append(self.curpass)

        self.curpassdur = Gtk.MenuItem(" ")
        self.menu.append(self.curpassdur)

        self.curpassrise = Gtk.MenuItem(" ")
        self.menu.append(self.curpassrise)

        self.curpassset = Gtk.MenuItem(" ")
        self.menu.append(self.curpassset)

        self.sep1 = Gtk.SeparatorMenuItem()
        self.menu.append(self.sep1)

        #future items
        self.futpass = Gtk.MenuItem(" ")
        self.menu.append(self.futpass)

        self.sep2 = Gtk.SeparatorMenuItem()
        self.menu.append(self.sep2)

        #Options

        self.aboutmenu = Gtk.MenuItem("About")
        self.aboutmenu.connect("activate", self.onabout)
        self.menu.append(self.aboutmenu)

        self.quit = Gtk.MenuItem("Quit")
        self.quit.connect("activate", self.quitnow)
        self.menu.append(self.quit)

        self.curpass.show()
        self.sep1.show()
        self.futpass.show()
        self.sep2.show()
        self.aboutmenu.show()
        self.quit.show()
        self.ind.set_menu(self.menu)

        #get iss data
        self.updatecache()
        self.checkiss()

        Gtk.main()


    #define code to hide or show icon
    def hideicon(self, w=None):
        self.ind.set_status (appindicator.IndicatorStatus.PASSIVE)

    def showicon(self, w=None):
        self.ind.set_status (appindicator.IndicatorStatus.ACTIVE)

    def quitnow(self, w=None):
        Gtk.main_quit()

    def onabout(self,widget):
        widget.set_sensitive(False)
        ad=Gtk.AboutDialog()
        ad.set_name("aboutdialog")
        ad.set_version("0.1")
        ad.set_copyright('Copyrignt (c) 2013 mh00h')
        ad.set_comments('Indicating ISS Zarya')
        ad.set_license(''+
        'This program is free software: you can redistribute it and/or modify it\n'+
        'under the terms of the GNU General Public License as published by the\n'+
        'Free Software Foundation, either version 3 of the License, or (at your option)\n'+
        'any later version.\n\n'+
        'This program is distributed in the hope that it will be useful, but\n'+
        'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n'+
        'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n'+
        'more details.\n\n'+
        'You should have received a copy of the GNU General Public License along with\n'+
        'this program.  If not, see <http://www.gnu.org/licenses/>.')
        ad.set_website('https://launchpad.net/~mh00h/+archive/issindicator')
        ad.set_website_label('ISSIndicator Homepage')
        ad.set_authors(['mh00h'])
        ad.run()
        ad.destroy()
        widget.set_sensitive(True)

    def updatecache(self, w=None):
        self.passingstatus = 'not set yet'
        #get ISS data from api
        self.ip = urllib2.urlopen("http://api.exip.org/?call=ip").read()
        self.geoip = json.load(urllib2.urlopen("http://freegeoip.net/json/"+self.ip))
        self.data = json.load(urllib2.urlopen("http://api.open-notify.org/iss/?lat="+str(self.geoip["latitude"])+"&lon="+str(self.geoip["longitude"])+"&alt=280&n=27"))

    def checkiss(self, w=None):
        self.n = 0
        self.passingstatus = "The ISS is not overhead."

        #check if cache is out of date and update if needed
        if time.time() > self.data['response'][len(self.data['response'])-1]['risetime']:
            self.updatecache
        for k in self.data['response']:
            duration = self.data['response'][self.n]['duration']
            risetime = self.data['response'][self.n]['risetime']
            settime = risetime + duration
            #print risetime, time.time(), settime
            if risetime <= time.time() <= settime:
                self.showicon()
                self.passingstatus = "The ISS is overhead"
                self.curpass.get_child().set_text(self.passingstatus)
                self.curpassdur.get_child().set_text("Duration: "+
                                                     str(time.strftime('%M:%S', time.gmtime(duration)))+" ("+
                                                     str(time.strftime('%M:%S', time.gmtime(time.time()-duration)))+" remaining)")
                self.curpassdur.show()
                self.curpassrise.get_child().set_text("Rise time: "+time.strftime('%H:%M:%S', time.gmtime(risetime)))
                self.curpassrise.show()
                self.curpassset.get_child().set_text("Set time: "+time.strftime('%H:%M:%S', time.gmtime(settime)))
                self.curpassset.show()
                break
            else:
                self.n += 1

        if self.passingstatus != "The ISS is overhead":
            self.curpass.get_child().set_text(self.passingstatus)
            self.curpassdur.hide()
            self.curpassrise.hide()
            self.curpassset.hide()
            #self.hideicon()

        #regardless of isspass, show the next pass time
        if self.n != len(self.data['response']):
            self.futpass.get_child().set_text("Next Pass: "+str(time.strftime('%H:%M:%S', time.gmtime(self.data['response'][self.n]['risetime'])))+" ("+str(time.strftime('%H:%M:%S', time.gmtime(self.data['response'][self.n+1]['risetime']-time.time())))+")")
        else:
            self.futpass.get_child().set_text("Next Pass: "+str(time.strftime('%H:%M:%S', time.gmtime(self.data['response'][0]['risetime'])))+" ("+str(time.strftime('%H:%M:%S', time.gmtime(self.data['response'][0]['risetime']-time.time())))+")")

if __name__ == '__main__':
    issindicator = indicator()

1 个答案:

答案 0 :(得分:1)

使用gobject.timeout_add安排回调定期进行。例如:

gobject.timeout_add(3600 * 1000, self.checkiss)

只要返回一个真值,就会定期从主循环调用该函数。如果您想要一次性功能,只需返回False,或允许它隐式返回None。要在特定时间点安排函数,请计算从现在到该点之间的时间,并在该时间段内调用timeout_add

当菜单激活时,重新安排功能更快;停用时,请再次将其设置为慢速。要重新安排此功能,请使用gobject.source_remove返回的值调用gobject.timeout_add,然后使用新的超时值调用timeout_add

gtk主循环将确保除非接收到事件或超时到期,否则不会唤醒进程。