[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

 

반응형

댓글()

파이썬으로 이미지 다운로드 하기

Computer 비관심/PyQt5|2020. 11. 10. 12:31
반응형

파이썬으로 이미지를 다운받으면 반복적인 이미지 다운로드 작업을 자동화 할 수 있다.

이 코드는 단순히 다운로드 하는 작업만 진행하지만 selenium이나 requests를 잘 섞어서 사용하면 자동으로 특정한 페이지의 이미지들을 다운 받을 수 있도록 만들 수 있다.

## 필요한 모듈을 불러온다.
import requests # to get image from the web
import shutil # to save it locally

## 다운로드할 이미지 URL
image_url = "http://~~~~.jpg"
filename = image_url.split("/")[-1]

# 스트림으로 이미지 얻어옴
r = requests.get(image_url, stream = True)

# 이미지가 잘 받아졌는지 확인
if r.status_code == 200:
    # 디코드 컨텐츠를 True로 세팅, 그렇지 않으면 파일 사이즈가 0
    r.raw.decode_content = True
    
    # 바이너리로 쓰기 권한으로 저장
    with open(filename,'wb') as f:
        shutil.copyfileobj(r.raw, f)
        
    print('Image sucessfully Downloaded: ',filename)
else:
    print('Image Couldn\'t be retreived')
반응형

댓글()

[pyqt5] 기본레이아웃 만들기

Computer 비관심/PyQt5|2020. 7. 24. 14:04
반응형

아래의 화면은 flutter 공식홈페이지에서 가져왔다. 플러터의 튜토리얼을 이용한 이유는 개념이 비슷하기 때문이다. 

(이 개념은 html로 따지면 div에 이미 flex박스의 flex-direction: 속성이 걸려 있는 것과 같다. 하지만 플렉스박스 이전에 div를 float해서 레이아웃을 만드는 법과는 다르기 때문에 개념의 차이점을 정확히 아는게 중요할 것 같다.) 

 

 

아래의 화면은 Row와 Column 위젯이 엮여져서 만들어 졌다.(nested)

화면을 만들때 즉 큰 레이아웃부터 작은 레이아웃으로 만들어 나가면 된다.

 

 

위의 로우는 Row는 하나의 칼럼과 하나의 이미지로 구성되어 있다.

그리고 칼럼은 텍스트, 텍스트, 로우, 로우 위젯으로 구성되어 있다.

 

 

 

그렇다면 이러한 방법을 어떻게 PyQt5에 적용 할 수 있을까?

 

 

QHBoxLayout() 의 QH는 Q horizontal 을 의미한다. 즉 가로방향(로우)의 구성을 말한다. 

아래의 코드는 즉 row의 구성을 만든뒤 

 

hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(yesButton)
hbox.addWidget(noButton)
hbox.addStretch(1)

 

이러한 형식으로 가로의 레이아웃이 잡힌다.

  Yes button yes button  

 

 

QVBoxLayout() 즉, 세로방향의 구성에 넣는다.

vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
vbox.addStretch(1)

 

 
  yes button no botton  
 

 

이렇게 하면 기본적인 PyQT5의 기본적인 레이아웃을 잡을 수 있다.

반응형

댓글()

[PYQT5]레퍼런스 사이트

Computer 비관심/PyQt5|2020. 7. 18. 18:31
반응형

어떤 모듈이 어디에 속해있는지 쉽게 찾을 수 있다!

 

https://doc.bccnsoft.com/docs/PyQt5/

 

PyQt5 Reference Guide — PyQt 5.7 Reference Guide

 

doc.bccnsoft.com

 

 

반응형

댓글()

[PYQT5] 프린트 할 위젯 선택하고 프린트 하는 예제

Computer 비관심/PyQt5|2020. 7. 18. 18:30
반응형

간단한 예제로 어떻게 작동하는지 응용하기 쉬운 소스입니다.

 

QPrinter 클레스를 사용해서 출력합니다.

import sys

from PyQt5 import QtGui, QtWidgets, QtPrintSupport


class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        # Create some widgets
        self.setGeometry(500, 500, 300, 300)
        self.button = QtWidgets.QPushButton(
            'Print QTextEdit widget (the one below)', self)
        self.button.setGeometry(20, 20, 260, 30)
        self.editor = QtWidgets.QTextEdit(
            'Wow such text why not change me?', self)
        self.editor.setGeometry(20, 60, 260, 200)
        self.button.clicked.connect(self.print_widget)

    def print_widget(self):
        # Create printer
        printer = QtPrintSupport.QPrinter()
        # Create painter
        painter = QtGui.QPainter()
        # Start painter
        painter.begin(printer)
        # Grab a widget you want to print
        screen = self.editor.grab()
        # Draw grabbed pixmap
        painter.drawPixmap(10, 10, screen)
        # End painting
        painter.end()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = App()
    gui.show()
    app.exec_()

 

만약 전체를 출력하고 싶다면 screen =self.editor.grab() 대신 screen = self.grab()을 하면 됩니다.

 

출처: https://stackoverflow.com/questions/42455904/printing-from-main-page-in-pyqt5

반응형

댓글()

Visual studio code에서 indentation 일괄적용

Computer 비관심/PyQt5|2019. 9. 22. 18:54
반응형

개발회사에서 장고로 웹사이트를 개발할 때는 pycharm을 이용해서 개발을 했다. 개인적으로 난 pycharm을 좋아하지 않았다. 프로그램 자체가 무겁다는 느낌이 많이 들었기 때문이다. 그때 아톰에디터도 유행 하고 있었는데 가볍고 좋았는데 이상한 잔버그들이 있었다. 

 

visual studio code를 알게 되고 visual code로 자바스크립트를 코딩을 했는데 배경, 폰트, 속도 전부다 만족스러웠다.

정말 최고의 에디터라고 말할 수 있다.

 

내가 파이썬을 좋아하고 파이썬 개발자가 되었던 이유는 파이썬이 정말 간결했기 때문이다.

하지만 visual studio code를 사용할 때 마다 인덴테이션 문제가 발생하였다.

 

 

문제 해결 방법

Space:4로 바꾸어 준다. pep8 ( 코딩스텐다드 )에서 인덴테이션을 스페이스바 4개로 권장하고 있기 때문에 탭을 클릭 했을때 스페이스바 4개가 적용이 되도독 설정한 것이다. 

 

 

 

그 결과 탭 클릭시 깔끔한 인덴테이션을 볼 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

하지만 이건 일시적인 방법일 뿐이다. 다시 에디터를 열게되면 탭의 space가 2가 되버린다.

그럼 기본세팅 자체를 바꿔보자.

 

1. shift + ctr + p를 누른다.

2. open user settings를 검색한다.

3. indent를 검색한다.

4.Tab size - the number of spaces a tab is equal to. (한번의 탭이 얼마의 스페이스와 같은지를 설정하는 것이다.)

tab size란의 숫자를 아래 스크린 샷 처럼 4로 바꾸어준다.

 

반응형

댓글()

PyQt에 firestore 연결하고 exe 파일로 만들기 (2)

Computer 비관심/PyQt5|2019. 9. 14. 01:11
반응형

파이어베이스와 PYQT의 조화는 잘 사용하지 않는지 자료가 그다지 많지 않았다.

디버깅 하는 스스로 만들어내고 PYQT와 FIREBASE에서 발생하는 버그의 해결책들을 찾는데 시간이 오래걸렸다.

 

 

PyQ에 firestore연결하고 exe 파일 만들기- 파이어스토어 파이썬에 연동하는법(1)

https://infocentre.tistory.com/45 

 

 

1. 파이인스톨러 사용

 

(1) 파이인스톨러(pyinstaller)를 사용한다. 

- 파이인스톨러의 간단한 사용 방법은 이전 글에 적어 두었다. 

https://infocentre.tistory.com/3

 

2. 디버깅 (디버깅을 쉽게 하는 방법을 모르면 개고생합니다.)

 

(1). 파일인스톨러를 사용할때 디버깅을 위해서 처음엔 -w 플레그를 붙이지 않고 실행 파일을 만든다.

-w 플래그를 붙이면 console창이 나오지 않아서 어떤 버그가 발생했는지 알기 힘들다. 이렇게 해야 하는 이유는 잘 동작하던 파이썬 큐티프로그램이 exe파일로 만들면 실행이 안되는 경우가 있기 때문이다.

 

(2)try except 구문을 잘 이용한다. 

try:
	#실행할 코드 넣기~
    
except Exception as e: 
	print(e) #에러를 표시하기 위해서
	input() #멈추게 하기 위해서

 

이 구문은 app.exec_() 이전에 써 넣어야 디버깅 화면이 꺼지지 않는다.

 

3. 이렇게 해서 디버깅을 해보면 The 'google-cloud-firestore' distribution was not found and is required by the application 라는 에러가 나온다.

 

- 파이썬 인스톨러가 구글클라우드 파이어베이스 스토어를 실행 시키지 않는것이다. 그래서 훅을 만들어준다.

\Lib\site-packages\PyInstaller\hooks 에 들어가서 hook-google.cloud.py 파일에 아래 코드를 추가해준다.

 

datas += copy_metadata('google-cloud-firestore')

 

 

4. 그리고 다시 실행해보면 잘 되거나 아니면 이런 버그가 발생한다.

Exception ignored in: 'grpc._cython.cygrpc.ssl_roots_override_callback'
E0913 23:26:43.750000000  9436 src/core/lib/security/security_connector/ssl_utils.cc:448] assertion failed: pem_root_certs != nullptr

 

이번엔 hooks폴더에  hook-grpc.py를 만들고 아래와 같은 코드를 넣는다.

 

from PyInstaller.utils.hooks import collect_data_files

datas = collect_data_files('grpc')

 

작동한다! 

 

참조: https://stackoverflow.com/questions/55848884/google-cloud-firestore-distribution-doesnt-get-added-to-pyinstaller-build

 

5. pyqt5 5.13 버전과 파이인스톨러를 같이 사용할 경우 다른 컴퓨터로 옮겼을때 작동이 안될 수 있다.

에러 - ImportError: unable to find Qt5Core.dll on PATH

- 이 경우 가장 쉬운 해결 방법은 이전 버전으로 다운그레이드 하는 것이다.

pip install pyqt5==5.12.2

 

참조 : https://stackoverflow.com/questions/56949297/how-to-fix-importerror-unable-to-find-qt5core-dll-on-path-after-pyinstaller-b

 

 

 

 

 

 

 

 

반응형

댓글()

PyQt에 firestore 연결하고 exe 파일로 만들기 (1)

Computer 비관심/PyQt5|2019. 9. 12. 00:53
반응형

처음 설치하는 것은 아래와 같이 firebase사이트에 들어가면 나와있다.

https://firebase.google.com/docs/firestore/quickstart

 

아래와 같이 pip을 사용해서 firebase-admin을 다운 받는다.

 

 

이제 데이타베이스에 접속하는 코드를 입력한다.

여기서 Certificate() 라는 함수에 json 형식의 퍼미션 정보를 넣어야 한다.

 

이 인증정보는 파이어베이스 콘솔로 들어와 project overview 옆에 있는 기어창을 누르고 project settings를 누른뒤

 

service accounts > python 버튼을 클릭하면 generate new private key 라는 버튼을 발견 할 수 있다.

그걸 클릭하면 Certificate()에 들어갈 정보를 다운 받을 수 있다.

그 뒤 

 

넣고 빼고 하는건 아래처럼 사이트에 나온데로 하면 된다.

 

 

 

다음은 exe file로 만드는 것을 할 것이다.

반응형

댓글()