python - 每秒更新 GTK+ MenuItem 倒计时,并定期调用函数

标签 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()

最佳答案

使用gobject.timeout_add安排回调定期发生。例如:

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

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

当菜单被激活时,重新安排功能以更快地发生;停用后,再次放慢速度。如需重新安排事件,请调用gobject.source_removegobject.timeout_add 返回的值,然后调用timeout_add使用新的超时值。

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

关于python - 每秒更新 GTK+ MenuItem 倒计时,并定期调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14983279/

相关文章:

swift - '不安全指针<Int8 >' has no member ' toString'

linux - 在 Cairo 支持下构建 Pango

python - Pygtk 选项卡中的 TreeView

python - 使用 PyGTK 的右键单击菜单(上下文菜单)

python - 如何将 Python 进程的输出重定向到 Rust 进程?

python - 如何有效地混淆 Python 代码?

python - 单击按钮时如何禁用文本抖动?

python - 是否可以优先锁定锁?

python - 将数组中连续相等的数字设置为零

python - webkit:是否可以将 cookie 存储到文件中并再次使用?