2026년 4월 18일 토요일

파이썬 GUI 환경 곁다리로 배포하기

예전에 mfc나 윈폼으로 메시지 드리븐 기반의 GUI 프로그래밍을 해오던 경험을
해온 나는 GUI라는것이 명령기반으로만 생각을 해왔다..

그러다가 안드로이드가 나왔고 xml기반의 뷰드로잉이 희안하다고 생각했고
플러터가 나와서 메서드 체이닝식 랜더링을 보면서 더이상 디자인에 대한 부분이 
명령기반이 아닌 분리되어 랜더링되게 만들어야 한다는 생각으로 바뀌었다.

그래서 아발로니아 같은것을 다루면서 이런 생각이 완전히 바뀌었다.
헌데.. 이런 구조를 처리할때는 디자인 패턴이라는것이 중요하다 MVVM이나 
DI 뷰협상 이런것들..
그런데 이런것들은 당연히 좋은데 빨리 뭔가를 GUI로 만들고 싶어하는 상황에서는
이러한 아키텍쳐가 오히려 에너지를 빼는 일이 되어 버릴 수 있다..

이상황에서는 드레그 드롭방식으로 뷰를 만들고 명령기반 코딩방식이 유의미 
할것이다. 헌데 나한테는 이 윈폼이 좋기는한데 뭔가 인스턴스 적인 느낌이 
없달까?? 이런 느낌이다. 빌드도 해야하고 요즘에는 실행시 런타임도 깔아야한다.

해서 이 중간 어디쯤을 커버칠수 있는부분을 찾다가 PyQt에 머무르게 되었다.
파이썬도 GUI라고 하면 tkinter, wxpython, kivy 이런것들이 많다..
하지만 지금에 와서는 디자이너가 있고 파일로 분리되는 깔끔함은 사실상 PyQt로
대동단결 되는 느낌이다.  tkinter에서 pack() 이런거 나열하고 있으면
디자인도 구린데 이렇게 까지 해야하나.. 이런 생각이 든다.
그래서 결론적으로 pyqt를 이용할 생각인데 이게 배포하는게 귀찮을 수 있다.
중간 어디쯤인 프로그램 답게 그냥 코드는 노출되어 상관이 없을것이고
콘솔은 사용자가 힘들게 접근할테니까.. 이 pyqt를 잘 배포하는것이 문제로 떠올랐다.


[본론으로 들어가서]

파이썬이 깔려있다는 전재하에 윈도우로 배포(이 개념이 리눅스도 먹힐것이다.) 한다고
가정하면 bat파일로 실행시킬때 가상환경인 venv폴더를 만들고 그때 reqlist.txt
파일을 읽어서 그 안의 내용을 pip install 처리하면 될것이다.
그리고 다음 실행시에는 그 vevn폴더가 있고 그 안에 installed.txt 파일이 설치완료를
말하고 있을테니 바로 실행하면 되겠다.  그리고 실행파일은 main.py이다.



- bat파일의 내용 -

@echo off
pushd "%~dp0"

if not exist "venv\installed.txt" (
    echo Ready for Launch..
    rmdir /s /q venv 2>nul
    python -m venv venv
    call venv\Scripts\activate

    python -m pip install --upgrade pip
    if exist "reqlist.txt" pip install -r reqlist.txt    
    echo OK > venv\installed.txt
) else (
    call venv\Scripts\activate
)

start pythonw main.py
exit



이렇게 작성해서 전달하면 GUI 기반으로 프로그램을 전달할수 있다.

아래는 main.ui 파일을 사용하는 기본 윈도우 프레임틀  
(QMainWindow의 minimumsize를 설정해주기 잊지마~)
(reqlist.txt 에는 기본적으로 PySide6 가 들어가 있어야겠쥬)


from PySide6.QtWidgets import *
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import QFile
import sys

#
class MyApp(QMainWindow):
    def __init__(self):
        super().__init__()        
        #        
        loader = QUiLoader()
        file = QFile("main.ui")
        if file.open(QFile.ReadOnly):
            self.ui_content = loader.load(file)            
            self.setCentralWidget(self.ui_content)
            file.close()        
        
    # 종료 이벤트
    def closeEvent(self, event):
        QApplication.quit()
        event.accept()

#
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec())


댓글 없음:

댓글 쓰기