Welcome, guest | Sign In | My Account | Store | Cart
# Based on this file: 
#   https://github.com/pallets/werkzeug/blob/master/werkzeug/_reloader.py


import time, os, sys, subprocess

PY2 = sys.version_info[0] == 2

class Reloader(object):

    RELOADING_CODE = 3
    def start_process(self):
        """Spawn a new Python interpreter with the same arguments as this one,
        but running the reloader thread.
        """
        while True:
            print("starting Tkinter application...")

            args = [sys.executable] + sys.argv
            new_environ = os.environ.copy()
            new_environ['TKINTER_RUN_MAIN'] = 'true'

            # a weird bug on windows. sometimes unicode strings end up in the
            # environment and subprocess.call does not like this, encode them
            # to latin1 and continue.
            if os.name == 'nt' and PY2:
                for key, value in new_environ.iteritems():
                    if isinstance(value, unicode):
                        new_environ[key] = value.encode('iso-8859-1')

            exit_code = subprocess.call(args, env=new_environ,
                                        close_fds=False)
            if exit_code != self.RELOADING_CODE:
                return exit_code

    def trigger_reload(self):
        self.log_reload()
        sys.exit(self.RELOADING_CODE)

    def log_reload(self):
        print("reloading...")

def run_with_reloader(root, *hotkeys):
    """Run the given function in an independent python interpreter."""
    import signal
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
    reloader = Reloader()
    try:
        if os.environ.get('TKINTER_RUN_MAIN') == 'true':

            for hotkey in hotkeys:
                root.bind_all(hotkey, lambda event: reloader.trigger_reload())
                
            if os.name == 'nt':
                root.wm_attributes("-topmost", 1)
                root.after(1000, lambda:app.wm_attributes("-topmost", 0))

            root.mainloop()
        else:
            sys.exit(reloader.start_process())
    except KeyboardInterrupt:
        pass

if __name__ == "__main__":
    from tkinter import Tk, Label
    
    class App(Tk):
        def __init__(self):
            Tk.__init__(self)

            Label(self, text="Press Control+r to reload...").pack()

    run_with_reloader(App(), "<Control-R>", "<Control-r>")

Diff to Previous Revision

--- revision 3 2016-10-24 16:43:21
+++ revision 4 2016-11-11 18:04:03
@@ -6,13 +6,14 @@
 
 PY2 = sys.version_info[0] == 2
 
-class ReloaderLoop(object):
+class Reloader(object):
 
-    def restart_with_reloader(self):
+    RELOADING_CODE = 3
+    def start_process(self):
         """Spawn a new Python interpreter with the same arguments as this one,
         but running the reloader thread.
         """
-        while 1:
+        while True:
             print("starting Tkinter application...")
 
             args = [sys.executable] + sys.argv
@@ -23,36 +24,40 @@
             # environment and subprocess.call does not like this, encode them
             # to latin1 and continue.
             if os.name == 'nt' and PY2:
-                for key, value in iteritems(new_environ):
-                    if isinstance(value, text_type):
+                for key, value in new_environ.iteritems():
+                    if isinstance(value, unicode):
                         new_environ[key] = value.encode('iso-8859-1')
 
             exit_code = subprocess.call(args, env=new_environ,
                                         close_fds=False)
-            if exit_code != 3:
+            if exit_code != self.RELOADING_CODE:
                 return exit_code
 
     def trigger_reload(self):
         self.log_reload()
-        sys.exit(3)
+        sys.exit(self.RELOADING_CODE)
 
     def log_reload(self):
         print("reloading...")
 
-def run_with_reloader(App, *hotkeys):
+def run_with_reloader(root, *hotkeys):
     """Run the given function in an independent python interpreter."""
     import signal
     signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
-    reloader = ReloaderLoop()
+    reloader = Reloader()
     try:
         if os.environ.get('TKINTER_RUN_MAIN') == 'true':
-            app = App()
 
             for hotkey in hotkeys:
-                app.bind_all(hotkey, lambda event: reloader.trigger_reload())
-            app.mainloop()
+                root.bind_all(hotkey, lambda event: reloader.trigger_reload())
+                
+            if os.name == 'nt':
+                root.wm_attributes("-topmost", 1)
+                root.after(1000, lambda:app.wm_attributes("-topmost", 0))
+
+            root.mainloop()
         else:
-            sys.exit(reloader.restart_with_reloader())
+            sys.exit(reloader.start_process())
     except KeyboardInterrupt:
         pass
 
@@ -65,4 +70,4 @@
 
             Label(self, text="Press Control+r to reload...").pack()
 
-    run_with_reloader(App, "<Control-R>", "<Control-r>")
+    run_with_reloader(App(), "<Control-R>", "<Control-r>")

History