web-dev-qa-db-fra.com

Rapide et facile: trayicon avec python?

J'aurais juste besoin d'un exemple rapide sur la façon de mettre facilement une icône avec python sur ma barre d'état système. Cela signifie: j'exécute le programme, aucune fenêtre ne s'affiche, juste une icône de plateau (I ' ai un fichier png) apparaît dans le systray et quand je clique dessus avec le bouton droit un menu apparaît avec quelques options (et quand je clique sur une option, une fonction est exécutée). Est-ce possible? Je n'ai besoin d'aucun fenêtre du tout ...

Les exemples/extraits de code sont vraiment appréciés! :RÉ

35
Marco Moschettini

Pour Windows et Gnome

Voilà! wxPython est la bombe. Adapté de la source de mon application 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()
59
FogleBird

wx.PySimpleApp déconseillé, voici comment utiliser wx.App à la place

Cela m'a pris du temps pour comprendre cela, alors j'ai pensé partager. wx.PySimpleApp est déconseillé dans wxPython 2.9 et au-delà. Voici le script original de FogleBird utilisant wx.App à la place.

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

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

Si vous pouvez garantir des fenêtres et que vous ne voulez pas introduire les fortes dépendances de wx, vous pouvez le faire avec les extensions pywin32 .

Voir aussi ceci question .

5
Mark

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

Multiplateforme

Voir PyQt: Afficher le menu dans une application de la barre d'état système

5
Jonathan

Oui. Il y a un exemple multiplateforme sur wiki.wxpython.org que j'ai testé avec python 2.7 (installation de minconda) sur macOS High Sierra (10.13.3), Windows 7 et gnome 3/centos7. Il est ici (ignorez le titre de la page): https://wiki.wxpython.org/Custom%20Mac%20OsX%20Dock%20Bar%20Icon

De petits mods sont nécessaires pour python 3.6:

  • vous devez importer wx.adv
  • wx.TaskBarIcon devient wx.adv.TaskBarIcon
  • wx.IconFromBitmap devient wx.Icon

Gnome 3 a nécessité l'installation de TopIcons Plus.

Puisque vous ne voulez pas que la fenêtre s'affiche ("aucune fenêtre n'apparaît, juste une icône de plateau"), commentez simplement la ligne suivante (bien que vous souhaitiez toujours conserver le parent wx.Frame):

frame.Show(True)

Et puisque vous souhaitez utiliser votre propre icône .png, supprimez l'image WXPdemo et les images intégrées et remplacez

icon = self.MakeIcon(WXPdemo.GetImage())

avec, par exemple

icon = wx.Icon('icon.png')

D'après mon expérience, cela constituera un bon point de départ pour s'adapter ou s'étendre davantage.

2
Generic Ratzlaugh

Une alternative si vous essayez d'exécuter un programme basé sur python en arrière-plan, vous pouvez l'exécuter en tant que service. Découvrez cette recette d'état actif, c'est assez utile. Je crois qu'une des options est de convertissez votre application en exe avec py2exe ou pyinstall.

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

2
jkdba

Pour un exemple, reportez-vous à ce fil -> question wx.

wxPython "classic" -> [new API] wxPython 'Phoenix' (Py3)

1
viteck