2

I've written a program using tkinter which when the main window is closed is supposed to be minimized to the system tray. But when I try to exit the program clicking "Close" in the tray that triggers the following function:

def quit_window(icon, item):
    icon.stop() # Удаление иконки из трея
    sys.exit(0) # Завершение программы

But it does not work and throws the following exception:

An error occurred when calling message handler
Traceback (most recent call last):
  File "C:\Users\a-par\mini_library_2020\env\lib\site-packages\pystray\_win32.py", line 386, in _dispatcher
    return int(icon._message_handlers.get(
  File "C:\Users\a-par\mini_library_2020\env\lib\site-packages\pystray\_win32.py", line 207, in _on_notify 
    descriptors[index - 1](self)
  File "C:\Users\a-par\mini_library_2020\env\lib\site-packages\pystray\_base.py", line 267, in inner
    callback(self)
  File "C:\Users\a-par\mini_library_2020\env\lib\site-packages\pystray\_base.py", line 368, in __call__
    return self._action(icon, self)
  File "c:/Users/a-par/mini_library_2020/LC.pyw", line 2976, in quit_window
    sys.exit(0)
SystemExit: 0

Also there's a VK bot in the program which is supposed to work when the program is minimized (it's the reason for actually minimizing to the tray). The bot works in a different from GUI thread. I tried to delete the bot fully but it didn't any help. Maybe the problem is threads but I don't think that way...

Minimally reproducible non-working code:

import pystray
import sys
import time
from PIL import Image
from pystray import Menu, MenuItem


def exit_action(icon):
    sys.exit(0)


def setup(icon):
    icon.visible = True
    
    i = 0
    while icon.visible:
        # Some payload code
        print(i)
        i += 1
        
        time.sleep(5)


def init_icon():
    icon = pystray.Icon('mon')
    icon.menu = Menu(
        MenuItem('Exit', lambda : exit_action(icon)),
    )
    icon.icon = Image.open('C:/Users/a-par/mini_library_2020/logo.ico')
    icon.title = 'tooltip'

    icon.run(setup)

init_icon()

Video

DGDays
  • 76
  • 12
  • Well instead of `sys.exit(0)`, I use `exit()`. To read more about the difference read [this](https://stackoverflow.com/questions/6501121/difference-between-exit-and-sys-exit-in-python). Also the error is just telling you that that function wants to close the program. Nothing more – TheLizzard Apr 07 '21 at 14:00
  • @TheLizzard, I understand, but it doesn't let you close the program. Because of this, the function does not work as it should. Also, when `exit()` displays an error, but instead of `0`, the value is `None` – DGDays Apr 07 '21 at 14:11
  • I think you should ignore the error because technically each time you close any python program it raises an error and that is how it closes. – TheLizzard Apr 07 '21 at 14:14
  • I would be happy, but only she continues to hang between two "worlds" and loads the system – DGDays Apr 07 '21 at 14:22
  • I am not that familiar with how `pystray` works but can you just set a global variable and when the variable is `True` you call `exit()` outside of that function? If that doesn't work I am, out of ideas – TheLizzard Apr 07 '21 at 14:27
  • @TheLizzard, Tried an idea like this, didn't help – DGDays Apr 07 '21 at 14:33

1 Answers1

2

sys.exit() will not work as it is not executed from the main thread or something. You need to use icon.stop() to close the event loop of pystray, thereby stopping the entire program.

Mach50
  • 61
  • 5