Taking control of the main loop.
Hey there,
I really like the package, it's doing what I want, and behaves as expected.
There is a single thing I would like to have and I would write the PR for it: I want to be in control of the main loop, like this:
import random
import pystray
class MyApp:
def __init__(self):
self.pystrayIcon = pystray.icon("foo")
def whatever(self):
print("bar")
r = random.random()
if r < 0.01:
return True
else:
return False
def main(self):
while True:
r = self.whatever()
self.pystrayIcon.mainstep() # this would be new
if r:
self.pystrayIcon.stop()
break
if __name__=="__main__":
myapp_instance = MyApp()
myapp_instance.main()
From what I can see, all that's required is to not while True: yield the events?
Would you accept such a PR?
Thank you for you suggestion!
I agree that this would be a very helpful addition, and if you managed I would certainly accept such a merge request. I think, however, that it may not be possible to implement for all supported backends, and I am very reluctant to add special functionality for single backends.
I agree that the idea is to have a unified solution, so if a specific exception has to be made, that would be bad. Are there tests to find out if a solution would work? Or would it have to be a manual trial and error?
Anyway, now that you've given your ok, I think it's worth the time to investigate. So I will do that.
HI,I think you could add a class to handle the pystray event and just run a new thread to start it. This is my code:
However, The window destroyed but the process doesn't exit when the on_quit event triggered. I don't know why.😅
# trayEvent.py
import sys
import pystray
class TrayEventHandler:
def __init__(self, root) -> None:
self.root_window = root
self.tray = None
def setTray(self, icon):
self.tray = icon
def start(self):
self.tray.run()
def on_quit(self):
self.root_window.destroy()
self.tray.stop()
# Mainwindow.py
class Mainwindow:
def __init__(self, root: tk.Tk, width=500, height=180) -> None:
self.root = root
self.width = width
self.height = height
self.stay_in_tray()
def stay_in_tray(self):
handler = TrayEventHandler(self.root)
menus = (
pystray.MenuItem("Exit", handler.on_quit),
)
image = Image.open('resources/q.jpg')
icon = pystray.Icon("name", icon=image, title="timing", menu=menus)
handler.setTray(icon)
threading.Thread(target=handler.start).start()
Hey there,
I really like the package, it's doing what I want, and behaves as expected.
There is a single thing I would like to have and I would write the PR for it: I want to be in control of the main loop, like this:
import random import pystray class MyApp: def __init__(self): self.pystrayIcon = pystray.icon("foo") def whatever(self): print("bar") r = random.random() if r < 0.01: return True else: return False def main(self): while True: r = self.whatever() self.pystrayIcon.mainstep() # this would be new if r: self.pystrayIcon.stop() break if __name__=="__main__": myapp_instance = MyApp() myapp_instance.main()From what I can see, all that's required is to not
while True: yieldthe events?Would you accept such a PR?
@xjackzenvey, thank you for your suggestion.
This will however not work, as the main loop must be run on the main thread on macOS. The original solution with stepping through the main loop would also be difficult to implement on that platform.
I have recently considered a solution based on multiprocessing; I imagine that would provide the means to create an unlimited amount of "main loops". A simple queue could then be used to propagate events to the main process. The challenge would then be to still have dynamic menu generation run in the main process, but gaining control over the main loop would become a non-issue.