こんにちは、
私はこれに初心者です(私のためにそのように答えてください)。私の(2番目の)質問を修正した後、すべてのコードは簡単に実行できるはずです。実際、私のマシンでは問題なく動作しますが、おそらくあなたのマシンではまだそうではありません. 誰かが読みやすくするために、どこにでもコメントしようとしました。これは Ubuntu 12.10 マシンで実行されますが、私の問題を解決するために Linux を実行する必要はありません!
解決済み 1. コード レビュー: コードを確認する際に、より適切で適切な方法で物事を要約または実行する方法についての意見をいただければ幸いです。私の残りの質問は、私がすでに取り組んでおくべきだとわかっていることです。しかし、私のコーディングスタイルなどで何か他に見つけたことがあれば、率直に言ってください。すべての良いコメントに賛成票を投じます。
解決済み: 2. 相対アイコン パス: 次の場所:
/home/mh00h/workspace/issindicator/src/International_Space_Station_clip_art.svg
これは、このスクリプトと同じフォルダーへの絶対パスです。私はそれを望んでいません、このスクリプトを誰のマシンでも動作させたいのです。私はこれらを試しました:
$HOME/workspace...
(nothing in front) International_Space_Station_clip_art.svg
./International_Space_Station_clip_art.svg
しかし、それらはうまくいきませんでした。上の画像は私が使用しようとしているものです (はい、リストされている png の代わりに SVG があることは知っています、imgur の制限)。これがドキュメントです。それは「アイコンテーマパス」について語っています...多分それは何とかそれを行うでしょうか?または、おそらくすべてのプログラマーがアイコンを保存することが期待される標準ディレクトリがありますか?
3. 日時関数の集中: 本当に、これを機能させることができて幸運でした。私のやり方は回り道ですが、私が知る限り、うまくいきます。でも、その混乱を修正するためのより良い方法があると確信しています!! スクリプトの下部に、多数の datetime 要素があります。
解決済み: 4. Appindicator3 フック: 毎秒実行するのではなく、メニューが呼び出されたときにのみ GTK を更新したいと考えています。これはここで部分的に回答されましたが、「実現」の実装方法がよくわかりません。(うまくいけば、これはこれを尋ねるのに適切な場所ですか?)
ありがとうございました!
#!/usr/bin/env python
import json, urllib2, time, math, datetime, os, webbrowser
from dateutil import tz
#indicator
from gi.repository import Gtk, GObject
from gi.repository import AppIndicator3 as appindicator
class indicator():
def __init__(self):
#######Set this to "False" if IssIndicator should hide it's icon during normal runtime (default = True)
self.isiconhidden = True
#
#create indicator
self.ind = appindicator.Indicator.new (
"issindicator",
"/home/mh00h/workspace/issindicator/src/International_Space_Station_clip_art.svg",
#"indicator-messages",
appindicator.IndicatorCategory.APPLICATION_STATUS)
if self.isiconhidden == True:
self.ind.set_status (appindicator.IndicatorStatus.PASSIVE)
else:
self.ind.set_status (appindicator.IndicatorStatus.ACTIVE)
#this is used to keep track of the gtk refresh period
self.refreshvalue = False
#dropdown menu
#current pass menu 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 pass items
self.futpass = Gtk.MenuItem(" ")
self.futpass.connect("activate", self.onurl)
self.menu.append(self.futpass)
self.sep2 = Gtk.SeparatorMenuItem()
self.menu.append(self.sep2)
#Options items
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 at first run
self.updatecache()
self.checkiss()
Gtk.main()
#functions
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()
#open browser for more tracking info
def onurl(self, w=None):
webbrowser.open("http://www.n2yo.com/passes/")
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 <abcd@abcd.com'])
ad.run()
ad.destroy()
widget.set_sensitive(True)
#how often to run checkiss
def setrefresh(self, r):
#this clause is required to keep script from hanging
if r != self.refreshvalue:
self.refreshvalue = r
try:
self.reftime = GObject.source_remove(True)
except:
pass
try:
self.reftime = GObject.timeout_add(r, self.checkiss)
except:
pass
#
def updatecache(self, w=None):
#this will show in the menu until the update process completes
self.passingstatus = 'not updated 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=47"))
self.data = {"message": "success", "request": {"latitude": 45.0, "passes": 3, "altitude": 280, "longitude": -81.0, "datetime": 1361502063},
"response": [{"duration": 542, "risetime": time.time()+10}, {"duration": 642, "risetime": 1361560774}, {"duration": 593, "risetime": 1361566621}]}
def checkiss(self, w=None):
#so as to not overload api servers, this runs as a separate process
#this updates the timers
self.n = 0
self.passingstatus = "ISS Zarya is below the horizon"
#check if we've gone through cached iss passings and update api if needed
try:
#ignore errors in case internet is not accessible
#have a buffer of 5 passes remaining before updating cache
#at 2 passes left, stop the program to prevent the rest of the program from throwing codes
if time.time() > self.data['response'][len(self.data['response'])-5]['risetime']:
self.updatecache
except:
if time.time() > self.data['response'][len(self.data['response'])-2]['risetime']:
os.system("notify-send 'ISS Indicator tried multiple times to update its satellite cache but has run out of its cached track.' 'This may be due to a bad internet connection. The application will now quit.'")
Gtk.main_quit()
#get current time
current_utc = datetime.datetime.utcnow()
current_utc = current_utc.replace(tzinfo=tz.gettz('UTC'))
#iterate over all iss passes
for k in self.data['response']:
duration = self.data['response'][self.n]['duration']
risetime = self.data['response'][self.n]['risetime']
settime = risetime + duration
#if this iteration matches with the current time, do...
if risetime <= time.time() <= settime:
#make the countdown values for the current pass tick
#rise time calculations and date conversions to string format
currisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n]['risetime'])
currisetime_utc = currisetime_utc.replace(tzinfo=tz.gettz('UTC'))
currisetime_tz = currisetime_utc.astimezone(tz.tzlocal())
currisetime_tzstr = str("%02d" % (currisetime_tz.hour))+':'+str("%02d" % (currisetime_tz.minute))+':'+str("%02d" % (currisetime_tz.second))
#set time calculations and durations
cursettime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n]['risetime']+self.data['response'][self.n]['duration'])
cursettime_utc = cursettime_utc.replace(tzinfo=tz.gettz('UTC'))
cursettime_tz = cursettime_utc.astimezone(tz.tzlocal())
curremainingtimeleft = cursettime_utc - current_utc
curduration = cursettime_utc - currisetime_utc
z= curremainingtimeleft.seconds
zhours = z/60/60
zminutes = z/60-zhours*60
zseconds = z-zhours*60*60-zminutes*60
curremainingtimeleftstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds))
z= curduration.seconds
zhours = z/60/60
zminutes = z/60-zhours*60
zseconds = z-zhours*60*60-zminutes*60
curdurationstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds))
cursettime_tzstr = str("%02d" % (cursettime_tz.hour))+':'+str("%02d" % (cursettime_tz.minute))+':'+str("%02d" % (cursettime_tz.second))
#since the ISS is presently overhead, show the icon and update GTK menuitems to show timers on the ISS pass
self.showicon()
self.passingstatus = "ISS Zarya is above the horizon!"
self.curpass.get_child().set_text(self.passingstatus)
self.curpassdur.get_child().set_text("Duration: "+curdurationstr+" ("+curremainingtimeleftstr+" remaining)")
self.curpassdur.show()
self.curpassrise.get_child().set_text("Rise time: "+currisetime_tzstr)
self.curpassrise.show()
self.curpassset.get_child().set_text("Set time: "+cursettime_tzstr)
self.curpassset.show()
break
else:
#if this iteration of ISS passes does not match with current time, then increase self.n
self.n += 1
#regardless of results show the next pass time
#if the ISS is overhead, use the next dictionary key for data
if self.n != len(self.data['response']):
nextrisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][self.n+1]['risetime'])
else:
#if the ISS is not overhead, use the first key in the dictionary
nextrisetime_utc = datetime.datetime.utcfromtimestamp(self.data['response'][0]['risetime'])
#calculate the next rise time and make timers
nextrisetime_utc = nextrisetime_utc.replace(tzinfo=tz.gettz('UTC'))
nextrisetime_tz = nextrisetime_utc.astimezone(tz.tzlocal())
remainingtimeleft = nextrisetime_utc - current_utc
z= remainingtimeleft.seconds
zhours = z/60/60
zminutes = z/60-zhours*60
zseconds = z-zhours*60*60-zminutes*60
remainingtimeleftstr = str(zhours)+':'+str("%02d" % (zminutes))+':'+str("%02d" % (zseconds))
nextrisetime_tzstr = str("%02d" % (nextrisetime_tz.hour))+':'+str("%02d" % (nextrisetime_tz.minute))+':'+str("%02d" % (nextrisetime_tz.second))
#update GTK menuitem
self.futpass.get_child().set_text("Next Pass: "+nextrisetime_tzstr+" ("+remainingtimeleftstr+")")
#if the ISS is not above the horizon, refresh GTK only once its time for the icon to be visible
if self.passingstatus != "ISS Zarya is above the horizon!":
self.setrefresh(remainingtimeleft.seconds*1000+100)
#self.setrefresh(1000)
self.curpass.get_child().set_text(self.passingstatus)
self.curpassdur.hide()
self.curpassrise.hide()
self.curpassset.hide()
if self.isiconhidden == True:
self.hideicon()
else:
#otherwise, refresh once a second to show the timers ticking in the menu
#test if the menu is active instead of always running like in this example
####MISSING CODE HERE##### DONT KNOW HOW TO DO IT, SO JUST SETTING TO 1 SEC
self.setrefresh(1000)
#for when setrefresh calls this function
return True
if __name__ == '__main__':
issindicator = indicator()