Rápido y fácil: ¿trayicon con python?
wxpython pyqt (8)
wx.PySimpleApp en desuso, aquí le indicamos cómo usar wx.App en su lugar
Me tomó un tiempo para resolver esto, así que pensé que iba a compartir. wx.PySimpleApp está en desuso en wxPython 2.9 y posteriores. Aquí está el script original de FogleBird usando wx.App en su lugar.
import wx
TRAY_TOOLTIP = ''System Tray Demo''
TRAY_ICON = ''icon.png''
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.AppendItem(item)
return item
class TaskBarIcon(wx.TaskBarIcon):
def __init__(self, frame):
self.frame = frame
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, ''Say Hello'', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, ''Exit'', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.IconFromBitmap(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print ''Tray icon was left-clicked.''
def on_hello(self, event):
print ''Hello, world!''
def on_exit(self, event):
wx.CallAfter(self.Destroy)
self.frame.Close()
class App(wx.App):
def OnInit(self):
frame=wx.Frame(None)
self.SetTopWindow(frame)
TaskBarIcon(frame)
return True
def main():
app = App(False)
app.MainLoop()
if __name__ == ''__main__'':
main()
Solo necesito un ejemplo rápido sobre cómo colocar fácilmente un icono con python en mi bandeja del sistema. Esto significa: ejecuto el programa, no aparece ninguna ventana, solo un icono de la bandeja (tengo un archivo png) aparece en la bandeja del sistema y cuando hago clic con el botón derecho aparece un menú con algunas opciones (y cuando hago clic en en una opción, se ejecuta una función). ¿Es eso posible? No necesito ninguna ventana en absoluto ...
Ejemplos / fragmentos de código son muy apreciados! :RE
Para Ubuntu
class TrayIcon:
def init():
iconPath = {"Windows":os.path.expandvars("%PROGRAMFILES%/MyProgram/icon.png"),
"Linux":"/usr/share/icons/myprogramicon.png"}
if platform.system()=="Linux":
import gtk
import appindicator # Ubuntu apt-get install python-appindicator
# Create an application indicator
try:
gtk.gdk.threads_init()
gtk.threads_enter()
icon = iconPath[platform.system()]
indicator = appindicator.Indicator("example-simple-client", "indicator-messages", appindicator.CATEGORY_APPLICATION_STATUS)
indicator.set_icon(icon)
indicator.set_status (appindicator.STATUS_ACTIVE)
indicator.set_attention_icon ("indicator-messages-new")
menu = gtk.Menu()
menuTitle = "Quit"
menu_items = gtk.MenuItem(menuTitle)
menu.append(menu_items)
menu_items.connect("activate", TrayIcon.QuitApp, menuTitle)
menu_items.show()
menuTitle = "About My Program"
menu_items = gtk.MenuItem(menuTitle)
menu.append(menu_items)
menu_items.connect("activate", TrayIcon.AboutApp, menuTitle)
menu_items.show()
indicator.set_menu(menu)
except:
pass
# Run the app indicator on the main thread.
try:
t = threading.Thread(target=gtk.main)
t.daemon = True # this means it''ll die when the program dies.
t.start()
#gtk.main()
except:
pass
finally:
gtk.threads_leave()
@staticmethod
def AboutApp(a1,a2):
gtk.threads_enter()
dialog = gtk.Dialog("About",
None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
label = gtk.Label("My Program v0.0.1, (C)opyright ME 2015. All rights reserved.")
dialog.vbox.pack_start(label)
label.show()
label2 = gtk.Label("example.com/n/nFor more support contact [email protected]")
label2.show()
dialog.action_area.pack_end(label2)
response = dialog.run()
dialog.destroy()
gtk.threads_leave()
@staticmethod
def QuitApp(a1, a2):
sys.exit(0)
Multiplataforma
Ver PyQt: Mostrar menú en una aplicación de la bandeja del sistema.
Para Windows y Gnome
¡Aqui tienes! wxPython es la bomba. Adaptado de la fuente de mi aplicación Feed Notifier .
import wx
TRAY_TOOLTIP = ''System Tray Demo''
TRAY_ICON = ''icon.png''
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.AppendItem(item)
return item
class TaskBarIcon(wx.TaskBarIcon):
def __init__(self):
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, ''Say Hello'', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, ''Exit'', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.IconFromBitmap(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print ''Tray icon was left-clicked.''
def on_hello(self, event):
print ''Hello, world!''
def on_exit(self, event):
wx.CallAfter(self.Destroy)
def main():
app = wx.PySimpleApp()
TaskBarIcon()
app.MainLoop()
if __name__ == ''__main__'':
main()
Para un ejemplo, consulte este hilo -> wx pregunta.
wxPython "classic" -> [new API] wxPython ''Phoenix'' (Py3)
Sí. Hay un ejemplo multiplataforma en wiki.wxpython.org que he probado con python 2.7 (instalación de minconda) en macOS High Sierra (10.13.3), Windows 7 y gnome 3 / centos7. Está aquí (ignora el título de la página): https://wiki.wxpython.org/Custom%20Mac%20OsX%20Dock%20Bar%20Icon
Se necesitan pequeños mods para python 3.6:
- debe importar wx.adv
- wx.TaskBarIcon se convierte en wx.adv.TaskBarIcon
- wx.IconFromBitmap se convierte en wx.Icon
Gnome 3 requirió la instalación de TopIcons Plus.
Ya que no desea que se muestre la ventana ("no se muestra ninguna ventana, solo un icono de bandeja"), simplemente comente la siguiente línea (aunque aún desea mantener el elemento primario wx.Frame):
frame.Show(True)
Y como desea usar su propio icono .png, elimine la imagen de WXPdemo y las imágenes de imágenes integradas y reemplace
icon = self.MakeIcon(WXPdemo.GetImage())
con, por ejemplo
icon = wx.Icon(''icon.png'')
En mi experiencia, esto proporcionará un buen comienzo para adaptarse o extenderse más.
Si puede garantizar Windows y no desea introducir las dependencias pesadas de wx, puede hacerlo con las extensiones pywin32 .
También vea esta question .
Una alternativa si está intentando ejecutar un programa basado en python en segundo plano, puede ejecutarlo como un servicio. Echa un vistazo a esta receta de estado activo es bastante útil. Creo que una de las opciones es convertir su aplicación a exe con py2exe o pyinstall.
Versión 2018
import wx.adv
import wx
TRAY_TOOLTIP = ''Name''
TRAY_ICON = ''icon.png''
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.Append(item)
return item
class TaskBarIcon(wx.adv.TaskBarIcon):
def __init__(self, frame):
self.frame = frame
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, ''Site'', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, ''Exit'', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.Icon(path)
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print (''Tray icon was left-clicked.'')
def on_hello(self, event):
print (''Hello, world!'')
def on_exit(self, event):
wx.CallAfter(self.Destroy)
self.frame.Close()
class App(wx.App):
def OnInit(self):
frame=wx.Frame(None)
self.SetTopWindow(frame)
TaskBarIcon(frame)
return True
def main():
app = App(False)
app.MainLoop()
if __name__ == ''__main__'':
main()