1

I'm creating a Tkinter-based GUI in Python. I would like the window to hide to system tray when it is minimized (using pystray module). It hides, but it only appears on the screen and hangs, when I'm trying to restore it.

Here's what I have tried:

from tkinter import *

from PIL import Image
import pystray


def hide_to_tray(_event=None):
    tray_icon = pystray.Icon("MyTrayIcon", title="My tray icon")  # create the tray icon
    tray_icon.icon = Image.open("app_icon.ico")  # open the icon using PIL
    tray_icon.menu = pystray.Menu(pystray.MenuItem("Open", lambda: tray_icon.stop(), default=True))  # create the menu
    root.withdraw()  # hide the window
    tray_icon.run()  # run the icon's main loop
    # icon mainloop
    root.deiconify()  # when the icon mainloop had been stopped, show the window again
    root.focus_force()  # focus on it

root = Tk()
btn = Button(root, text="Sample button")
btn.grid()
root.bind("<Unmap>", hide_to_tray)  # hide to tray on minimizing
root.mainloop()

How can I solve this problem?

Demian Wolf
  • 1,698
  • 2
  • 14
  • 34

1 Answers1

4

1. Use infi.systray

It runs on a seperate thread and thus won't block, install it with pip:

pip install infi.systray

Don't call tkinter methods from the info.systray thread:

Since infi.systray runs on a seperate thread, you mustn't call tkinter methods directly in the callback functions that you pass to the systray icon on creation. Use a thread safe way (e.g. queue) to inform the main thread about events in the systray icon instead!

2. Don't run pystray and tkinter at the same time

You can't run them both because they block the running thread and both have to run on the mainthread. See Osher's answer that only displays the system tray icon when the tkinter app is closed.

Bartimaeus
  • 86
  • 1
  • 7