0

I've created an executable file of my GUI python script using Pyinstaller (I used tkinter as the framework, and Anaconda3, Python 3.7 and I am on Windows 10). I have set it up to start automatically upon Windows startup, using Task Scheduler.

I have been asked to make it run in the system tray, silently, but not as a service (because sometimes it requires user interaction).

Thanks to the incredibly helpful users from here:

What's the simplest way to put a python script into the system tray (Windows)

Minimise Python to System Tray and Generate Notifications?

How to build a SystemTray app for Windows?

I have the win32py script that creates the system tray icon with some menu and simple functions. However, I can not figure out the very obvious thing of how to link my tkinter GUI script with this code.. I tried to execute my script using execfile().open() and make it run like a normal menu_action within the script, but it doesn't work.

Some discussions here:

Hide tkinter window in system tray

show that it is not possible to hide tkinter frames in the system tray. But as far as I understand, the script from above is independent on this.

I found out about this tcl extension tktray (https://core.tcl-lang.org/jenglish/gutter/packages/tktray.html) and I am now learning how to build it into tlc., which isn't as trivial as I thought. However, tktray is 10 years old so I don't have much hopes it will be compatible with current versions.

All other solutions I found were for other programming languages, other OS or using PyQ5. I would hate to rewrite my entire code with wxPython or PyQ5 just for this extra feature, so if anyone can help me out with linking my GUI script with the win32py script from above...

ISquared
  • 364
  • 4
  • 22
  • 1
    You could refer [this question](https://stackoverflow.com/questions/62372144/how-to-add-system-tray-to-my-tkinter-application-and-avoid-using-lots-of-pywin32) about how to use `winico`.Works fine on my PC. – jizhihaoSAMA Jul 31 '20 at 16:18
  • Thank you @jizhihaoSAMA ! Just a quick question, when you download the respective folder for 64- and 32-bit and it says to move in into the tcl directory and rename as winico. But then you have to add it as binary data to your pyinstaller, which assumes this data is in your current directory ?! Or does this refer to the script snippet they have showed there? Apologies for all the confusion :( – ISquared Aug 01 '20 at 18:06
  • 1
    When I used pyinstaller, I copied `winico` in both the path of script and the path of `tcl`. – jizhihaoSAMA Aug 02 '20 at 01:17
  • Thanks, I just did that! :) About the system tray icon, where is it supposed to be? In the code you have 2.ico as the icon name, so I changed the names of the .ico file in the winico folder to '2.ico', but it doesn't seem to find them. I also added 2.ico to my binary data in pyinstaller, and it still does not find them. What am I doing wrong? :( – ISquared Aug 02 '20 at 09:33
  • 1
    In my case the icon image and python script is in the same folder.I don't use `--add-data` to add tray icon. Just make them in the same path after I convert them to execute file. – jizhihaoSAMA Aug 02 '20 at 09:36
  • I tried to put it in the same folder as well, I'll try with a different .ico, thanks for the help!! – ISquared Aug 02 '20 at 09:39
  • I managed to make it work on my script, which doesn't use classes, so I just had to make it class-less :) Thank you so much, this saved my life! – ISquared Aug 02 '20 at 11:34

1 Answers1

2

In Tkinter, there's some helpful functions like:

root.withdraw() # to hide the window
root.deiconify() # to show the window
root.protocol() # control Tk's *protocols*
root.attributes() # control Tk's attributes that are only available in Tcl

So when you use those functions and this script altogether, I could create a script that can hide and show it's window when you toggle an option to hide/show it

After running root.mainloop() it'll turn the root variable into None so all attributes will disappear after that. I came up with the new idea: the program will initiates the program whenever you toggle the Open in new window option from your script from the system tray (ex. icon.ico). It will destroy itself when a person presses x on the top of the window.

So my script does not minimise the script into the system tray, but rather trick people that the script is minimised.

(note: I'm using Windows 10 version 1909)

from tkinter import *
from systrayicon import SysTrayIcon

def prog():
    root = Tk()
    root.title("Hello, world!")
    root.attributes('-toolwindow', True) # only shows the destroy button

    text = Label(root, text="Hello, world!")
    text.pack()

    root.mainloop()


def main():
    SysTrayIcon(open("./icon.ico", "r"), title, ('Open the main window', None, prog), on_quit=exit) # the function exit() is predefined, no need to worry

if __name__ == '__main__':
    main()
Honcky
  • 25
  • 6