2013-02-20 93 views
1

這是我的國際空間站指標。我正在嘗試創建一個顯示倒計時的GTK MenuItem。這將在使用AppIndicator3的Ubuntu Unity指標中。我希望此菜單項(futpass)每秒刷新一次(即實時倒計時),但也希望在未選擇菜單時保持不活動狀態,以免消耗系統資源。問題是,我無法自己刷新它。更新GTK + MenuItem每秒倒計時和定期函數調用

由於每次需要運行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

使用gobject.timeout_add安排回調定期發生。例如:

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

只要函數返回一個真值,就會從主循環中定期調用該函數。如果您想要一次性功能,只需返回False,或允許它隱式返回None。要在特定時間點安排功能,請計算從現在到該點之間的時間,並在該時間段內調用timeout_add

當菜單被激活時,重新調度功能發生得更快;當停用時,再次安排它緩慢。要重新調度函數,請用gobject.timeout_add返回的值調用gobject.source_remove,然後用新的超時值調用timeout_add

gtk主循環將確保進程不會被喚醒,除非它接收到事件或者超時到期。

+0

這真的很不錯,但我不知道如何在菜單被激活時掛鉤到菜單中;這是我最大的挑戰。 – mh00h 2013-02-20 23:24:34

+1

@ mh00h通常你會聽到父菜單條目(或按鈕或其他)的'activate'信號,但在這種情況下,你沒有它。也許你可以通過調整菜單項的「實現」信號來僞造它。 – user4815162342 2013-02-21 07:45:24

+1

@ mh00h您是否設法掛鉤菜單激活? – user4815162342 2013-02-22 10:34:46