Pygtk 状态图标无法加载?
我现在正在写一个小脚本,需要用到 gtk.StatusIcon()
。但不知道为什么,它的表现有点奇怪。如果我在 Python 的交互式命令行里输入:
>> import gtk
>> statusIcon = gtk.status_icon_new_from_file("img/lin_idle.png")
Pygtk 正常工作,会在系统托盘里显示一个图标(lin_idle.png):
但是,如果我在我的脚本里尝试做同样的事情:
def gtkInit(self): self.statusIcon = gtk.status_icon_new_from_file("img/lin_idle.png")
当调用 gtkInit()
时,我看到的是这个:
我在和交互式 Python 命令行相同的工作目录下运行脚本,所以我很确定它能找到这个图像,但我还是搞不懂... 有人有什么想法吗?谢谢大家。
更新:不知道为什么,在脚本里调用 gtk.status_icon_new_from_file()
几次后,它最终会创建图标,但这个问题依然存在。不知道有没有人能帮我找出问题出在哪里?
应要求:这是完整的脚本。其实这是我正在早期阶段制作的一个应用程序,但如果你设置正确,它现在是可以工作的,所以如果你想的话可以随便试试(也可以帮我!),你只需要获取一个 imgur 开发者密钥,并把它放在 linup_control.py
里。
Linup.py
# # Linup - A dropbox alternative for Linux! # Written by Nakedsteve # Released under the MIT License # import os import time import ConfigParser from linup_control import Linup cfg = ConfigParser.RawConfigParser() # See if we have a .linuprc file home = os.path.expanduser("~") if not os.path.exists(home+"/.linuprc"): # Nope, so let's make one cfg.add_section("paths") cfg.set("paths","watch_path", home+"/Desktop/screenshot1.png") # Now write it to the file with open(home+"/.linuprc","wb") as configfile: cfg.write(configfile) else: cfg.read(home+"/.linuprc") linup = Linup() # Create the GUI (status icon, menus, etc.) linup.gtkInit() # Enter the main loop, where we check to see if there's a shot to upload # every 1 second path = cfg.get("paths","watch_path") while 1: if(os.path.exists(path)): linup.uploadImage(path) url = linup.getURL() linup.toClipboard(url) linup.json = "" print "Screenshot uploaded!" os.remove(path) else: # If you're wondering why I'm using time.sleep() # it's because I found that without it, my CPU remained # at 50% at all times while running linup. If you have a better # method for doing this, please contact me about it (I'm relatively new at python) time.sleep(1)
linup_control.py
import gtk import json import time import pycurl import os class Linup: def __init__(self): self.json = "" def uploadImage(self, path): # Set the status icon to busy self.statusIcon.set_from_file("img/lin_busy.png") # Create new pycurl instance cu = pycurl.Curl() # Set the POST variables to the image and dev key vals = [ ("key","*************"), ("image", (cu.FORM_FILE, path)) ] # Set the URL to send to cu.setopt(cu.URL, "http://imgur.com/api/upload.json") # This lets us get the json returned by imgur cu.setopt(cu.WRITEFUNCTION, self.resp_callback) cu.setopt(cu.HTTPPOST, vals) # Do eet! cu.perform() cu.close() # Set the status icon to done... self.statusIcon.set_from_file("img/lin_done.png") # Wait 3 seconds time.sleep(3) # Set the icon to idle self.statusIcon.set_from_file("img/lin_idle.png") # Used for getting the response json from imgur def resp_callback(self, buff): self.json += buff # Extracts the image URL from the json data def getURL(self): js = json.loads(self.json) return js['rsp']['image']['original_image'] # Inserts the text variable into the clipboard def toClipboard(self, text): cb = gtk.Clipboard() cb.set_text(text) cb.store() # Initiates the GUI elements of Linup def gtkInit(self): self.statusIcon = gtk.StatusIcon() self.statusIcon.set_from_file("img/lin_idle.png")
2 个回答
你犯了两个错误,一个比较重要,另一个不太重要。
首先,如果你想使用系统自带的图标,可以用 .set_from_stock( stock_id ) 这个方法。如果你想用自己的图标,那就可以用 .set_from_file(/path/to/img.png) 这个方法。
另一个问题可能是主要原因,就是当你写 gtk 应用的时候,你必须调用 gtk.main() 这个函数。这个函数是 gtk 的主循环,负责处理所有信号、绘制窗口和其他 gtk 的事情。如果你不调用这个函数,你的图标就不会显示出来。
在你的情况下,解决方案是创建两个线程——一个用于图形界面(gui),另一个用于你的应用程序。在第一个线程中,你只需调用 gtk.main()。在第二个线程中,你放入你的主程序循环。当然,当你运行 Python 程序时,已经有一个线程在运行了:P
如果你对线程不太了解,还有其他解决方案。Gtk 有一个函数,可以在你指定的延迟后调用你指定的函数:
def call_me:
print "Hello World!"
gtk.timeout_add( 1000 , call_me )
gtk.timeout_add( 1000 , call_me )
gtk.main()
不过这个方法现在似乎已经不推荐使用了。可能他们已经找到了更好的解决方案。
你需要像qba说的那样调用gtk.main
这个函数,不过每隔N毫秒调用一个函数的正确方法是使用gobject.timeout_add
这个函数。在大多数情况下,你会希望把可能会让界面卡住的操作放在一个单独的线程里,但在你的情况中,因为你只是有一个图标,所以不需要这么做。除非你打算让这个状态图标有一个菜单。下面是我修改过的Linup.py
的一部分:
# Enter the main loop, where we check to see if there's a shot to upload
# every 1 second
path = cfg.get("paths","watch_path")
def check_for_new():
if(os.path.exists(path)):
linup.uploadImage(path)
url = linup.getURL()
linup.toClipboard(url)
linup.json = ""
print "Screenshot uploaded!"
os.remove(path)
# Return True to keep calling this function, False to stop.
return True
if __name__ == "__main__":
gobject.timeout_add(1000, check_for_new)
gtk.main()
你还需要在某个地方import gobject
。
我不确定这个是否有效,因为我无法安装pycurl
。
编辑:在linup_control.py
中,我建议你尝试把
# Wait 3 seconds
time.sleep(3)
# Set the icon to idle
self.statusIcon.set_from_file("img/lin_idle.png")
改成
gobject.timeout_add(3000, self.statusIcon.set_from_file, "img/lin_idle.png")