pyqt리로드에 해당하는 글 1

[TKINTER/PYQT] 티케이인터 자동 새로고침 적용하기(HOT RELOAD)

Computer 비관심/PyQt5|2022. 8. 29. 00:29
반응형

웹개발에서 코드를 수정하게 되면 자동으로 웹사이트가 리로드가 되면서 수정한 내용이 반영이 된다. 이는 개발을 훨씬 쉽고  편하고 쉽게 할 수있도록 도와준다. 이러한 기능이 없다면 코드가 수정이 될 때 마다 끄고 실행하고를 반복 해야 할 것이다. 이는 아주 고되고 짜증난다.

 

PYQT나 TKINTER를 가지고 간단하게 무엇인가를 만들어보려고 했는데 내용이 바뀔 때 마다 실행을 다시해줘야 했다. 

인터넷이 이와 관련된 정보가 있는지 찾아 보았고 아래의 코드를 찾았다.

# 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
            env = os.environ.copy()
            env['TKINTER_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 env.iteritems():
                    if isinstance(value, unicode):
                        env[key] = value.encode('iso-8859-1')

            exit_code = subprocess.call(args, env=env,
                                        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 application in an independent python interpreter."""
    import signal
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
    reloader = Reloader()
    try:
        if os.environ.get('TKINTER_MAIN') == 'true':

            for hotkey in hotkeys:
                root.bind_all(hotkey, lambda event: reloader.trigger_reload())
                
            if os.name == 'nt':
                root.wm_state("iconic")
                root.wm_state("zoomed")

            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>")

출처:https://code.activestate.com/recipes/580707-reload-tkinter-application-like-a-browser/

 

맨아래 코드 run_with_reloader 함수에 파라메터로 단축키를 넣고 그 단축키를 눌렀을때 프로그램을 재시작 해주는 코드이다.

 

 

그리고 아래는 https://www.daniweb.com/programming/software-development/code/260268/restart-your-python-program 에서의 코드를 바탕으로 파일이 해당되는 파일의 변화가 됬을때 자동으로 리로드가 되는 기능을 만들어 보았다.

 

os.stat('파일이름').st_mtime을 통해서 파일이 변화되기 전과 변화된 후의 값을 비교하여 비교된 값이 다르면 재시작을 하게 만든 것이다.

from distutils.log import debug
import sys
import os
from tkinter import Tk, Label, Button
import time
import threading

DEBUG=True
filename= './main2.py'
def debug_mode(is_debug):
    _cached_stamp = os.stat(filename).st_mtime
    while(is_debug):
        time.sleep(1.5)
        stamp = os.stat(filename).st_mtime
        if stamp != _cached_stamp:
            _cached_stamp = stamp
            restart_program()
            
t = threading.Thread(target=debug_mode,args=(DEBUG,))

def restart_program():
    """Restarts the current program.
    Note: this function does not return. Any cleanup action (like
    saving data) must be done before calling this function."""
    python = sys.executable
    os.execl(python, python, * sys.argv)

root = Tk()

t.start()



Label(root, text="Hello World1").pack()


root.mainloop()

 

그리고 이런 라이브러리를 찾았다. 이 모듈도 위와 원리는 비슷하고 importlib를 사용해서 리로드를 시킨다.

 

https://pypi.org/project/hotreload/ 

 

hotreload

Run any arbitrary python script every time the code changes in the file.

pypi.org

 

반응형

댓글()