pythonpython-3.xpystray

How to use multiple arguments calling a function in Pystray?


I'm trying to pass extra arguments to a function that is called by an item in pystray menu.

import pystray
from pystray import MenuItem as item
from PIL import Image, ImageTk

def show_window(icon):
    icon.notify('Hello World!', 'Hi')


def quit_window(icon, message):
    print(message)
    icon.stop()


icon = 'icon.ico'
image=Image.open(icon)

menu=pystray.Menu(item('Show', show_window, default=True), item('Quit', quit_window(icon, "Test")))
icon=pystray.Icon("name", image, "My System Tray Icon", menu)
icon.run()

In this example I'm trying to pass the argument "message" calling the function "quit_window" when I press "Quit" in pystray menu. The problem here is by default the functions used in menu construction don't have arguments and internally refers to icon. When I use arguments the constructor don't pass the icon reference to call stop() and since I create pystray.Icon after pystray.Menu I don't know how to pass this info and make it work.


Solution

  • You can sort of do what you appear to want to do but not like that.

    The item() takes a function (like show_window, note no brackets) not a function call like you used quit_window(icon,message) - but if you make the called function return a function then it will indirectly do what you want, although the message is fixed at compile time.

    Or you could make the function use a global to get the message it prints, which is a bit horrible but means the message is runtime changeable. Or you could probably do something with a class which at least wouldn't use an explicit global.

    Anyway those tow methods are shown here (i renamed all those references to icon because it was confusing):

    import pystray
    from pystray import MenuItem as item
    from PIL import Image, ImageTk
    
    def show_window(icon1):
        icon1.notify('Hello World!', 'Hi')
    
    globalmessage = "A global quit message"
    
    def quit_window(icon2):
        icon2.stop()
    
    def indirect_quit_window(icon2,message):
        print( f"The message on quit will be '{message}'" )
        def realquitfunction(icon2):
            print( message )
            icon2.stop()
        return realquitfunction
    
    
    def global_quit(icon4):
        global globalmessage
        print( globalmessage )
        icon4.stop()
    
    icon = 'icon.ico'
    image=Image.open(icon)
    
    menu=pystray.Menu(item('Show', show_window, default=True), item('Quit', indirect_quit_window(icon, "Quitting now - bye!")),item('Global Quit', global_quit) )
    
    icon3=pystray.Icon("name", image, "My System Tray Icon", menu)
    icon3.run()
    

    Output when starting then clicking Quit:

    The message on quit will be 'Quitting now - bye!'
    Quitting now - bye!
    

    Output when starting then clicking Global Quit:

    The message on quit will be 'Quitting now - bye!'
    A global quit message