Pregunta

Solo necesitaría un ejemplo rápido sobre cómo poner fácilmente un ícono con Python en mi systray. Esto significa: ejecuto el programa, no aparece ninguna ventana, solo un ícono de la bandeja (tengo un archivo PNG) aparece en el systray y cuando hago clic derecho en él 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 ...

¡Se agradecen los ejemplos / fragmentos de código! :D

¿Fue útil?

Solución

Para Windows y Gnome

¡Aqui tienes! Wxpython es la bomba. Adaptado de la fuente de mi Notificador de alimentación solicitud.

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

Otros consejos

wx.pysimplep en desacuerdo, aquí le mostramos cómo usar wx.app en su lugar

Me llevó a descubrir esto, así que pensé en compartir. wx.pysimplep está en desuso en Wxpython 2.9 y más allá. 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()

Si puede garantizar Windows y no desea introducir las fuertes dependencias de WX, puede hacerlo con el extensiones Pywin32.

También vea esto pregunta.

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 me@gmail.com")
    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 bandeja de sistema

Versión de 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()

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.

http://code.activestate.com/recipes/551780/

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í (ignore el título de la página):https://wiki.wxpython.org/Custom%20MAC%20OSX%20Dock%20Bar%20icon

Se necesitan pequeñas modificaciones para Python 3.6:

  • Debes importar wx.Adv
  • WX.TaskBaricon se convierte en wx.Adv.TaskBaricon
  • wx.iconfrombitmap se convierte en wx.icon

GNOME 3 Instalación requerida de Topess Plus.

Dado que no desea tener la pantalla de la ventana ("No aparece la ventana, solo un icono de la bandeja"), simplemente comente la siguiente línea (aunque aún desea mantener al padre WX.frame):

frame.Show(True)

Y dado que desea usar su propio icono .png, elimine la imagen wxpdemo y las cosas de incrustación 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top