Closed Ari24-cb24 closed 3 years ago
Found out, that this only happens, when passing on_quit
into SystrayIcon()
Fixed it with removing
menu_options = menu_options + (('Quit', None, SysTrayIcon.QUIT),)
in traybar.py and also building my own closing function with
import win32_adapter
menu = (
("Open", "./img/icon.ico", lambda st: print("Test")),
("Exit", None, self.__shutdown),
)
self.stray = SysTrayIcon("./img/icon.ico", "Name", menu_options=menu)
def __shutdown(self, *args):
win32_adapter.DestroyWindow(self.stray._hwnd)
print("CLOSE")
sys.exit(0)
Using SysTrayIcon.shutdown()
in the on_quit
will error because the event monitor thread calls your on_quit
function, which calls the shutdown
function, which tries the join the event loop thread (to wait for it to exit before returning). But if a thread joins itself to wait for it to exit, it would block forever, so the threading module just raises an exception. A way to fix this error without directly editing module code is to signal another thread to run the shutdown function. In my case, I was able to use the main thread, and just tell it to block until it gets the signal.
TL;DR Call the shutdown()
function in another thread to avoid the exception
Hey there again, sorry for the late answer,
I already tried calling the shutdown() function in another thread and I can't block the main Thread because I have other things running on the Mainthread.
But yeah, thanks for answering
https://github.com/Infinidat/infi.systray/issues/32#issuecomment-723479818
Call the shutdown() function in another thread to avoid the exception
Hi @pythonmcpi , I know this is very late comment but I am facing a similar situation.
Can you please provide a code example with respect to your comment. That would be really helpful
@dibakarbose I can try looking for my original project, but I don't know if I'll be able to find it. I have too many abandoned projects :(
EDIT So I somehow found it in the first project folder I looked in...
The code below is from a project that I ended up abandoning on November 7, 2020, exactly 2 hours and 5 minutes after writing my original comment. It probably requires an icon.ico
file to be present in the directory. (My original ico file can be found here - Github doesn't let me attach .ico files) I have no idea if my old code works or not, and the code quality isn't great.
Good luck.
#import pystray
import contextlib
with contextlib.redirect_stdout(None):
import pygame
import sys
import subprocess
import os
from PIL import Image, ImageDraw
from infi.systray import SysTrayIcon as sti
import time
#from pystray import Icon as picon, Menu as pmenu, MenuItem as pitem
class Launcher(object):
def __init__(self, width=860, height=680):
## self.icon = picon('Launcher', self.generate_icon(), menu=pmenu(
## pitem(
## 'Quit',
## self.quit
## )
## )
## )
self.width = width
self.height = height
self.hidden = False
self.menu = (("Toggle Visibility", None, lambda e: self.toggle_visible()),)
self.icon = sti("icon.ico", "Launcher", self.menu, on_quit=lambda e: self.quit())
pygame.init()
def run(self):
self.running = True
#self.icon.run()
self.icon.start()
self.screen = pygame.display.set_mode((self.width, self.height), pygame.NOFRAME)
self.mainloop()
def generate_icon(self):
# Checkerboard Pattern
width = 32
height = 32
color1 = (255, 255, 255)
color2 = (0, 0, 0)
icon = Image.new('RGB', (width, height), color1)
dc = ImageDraw.Draw(icon)
dc.rectangle(
(width // 2, 0, width, height // 2),
fill=color2)
dc.rectangle(
(0, height // 2, width // 2, height),
fill=color2)
return icon
def toggle_visible(self):
if not self.running:
return
self.hidden = not self.hidden
if self.hidden:
pygame.display.iconify()
else:
pygame.display.deiconify()
def mainloop(self):
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.icon.shutdown()
def quit(self):
self.running = False
#self.icon.stop()
#self.icon.shutdown() # Shutdown has a line that joins the event monitor thread, but this function is called by the monitor thread, causing a RuntimeError. This line can be put in mainloop (which runs on main thread)
pygame.quit()
if __name__ == "__main__":
launcher = Launcher()
launcher.run()
#launcher.generate_icon().save("icon.ico", "ICO") # Save icon file
Hey there,
Same issue as the one 2 years ago,
SystrayIcon.shutdown() produces a threading join error.