PySide6로 데스크톱 앱 만들기 #1 PySide6란 — Qt와 파이썬으로 데스크톱 앱

5 분 소요

모던 파이썬 기초까지 마치고 나면 파이썬으로 웬만한 자동화 스크립트와 CLI 도구는 만들 수 있습니다. 그런데 도구를 동료나 가족에게 건네주는 순간 벽을 만납니다. 터미널을 열어 본 적 없는 사람에게 “가상 환경을 활성화하고 스크립트를 실행하세요"라고 안내할 수는 없습니다. 버튼과 입력창이 있는 창 하나가 필요해지는 시점이고, 이 시리즈는 그 창을 만드는 법을 다룹니다. 파이썬 트랙의 데스크톱 확장입니다.

총 7편으로 구성됩니다.

  • #1 PySide6란 — Qt와 파이썬으로 데스크톱 앱 ← 이번 글
  • #2 위젯과 레이아웃 — 화면을 조립하는 법
  • #3 시그널과 슬롯 — 이벤트 처리의 핵심
  • #4 Qt Designer와 UI 파일 — 화면을 그려서 불러오기
  • #5 모델과 뷰 — 리스트·테이블에 데이터 연결
  • #6 스레드와 타이머 — 멈추지 않는 UI
  • #7 패키징과 배포 — PyInstaller로 실행 파일 만들기

이번 글은 파이썬 GUI 선택지 중에서 PySide6를 고르는 근거를 세우고, 설치 후 첫 창을 띄워 이벤트 루프가 무엇인지 확인하는 데까지 진행합니다.

파이썬 GUI의 선택지 #

파이썬으로 데스크톱 화면을 만드는 방법은 크게 세 갈래입니다.

갈래대표특징
표준 라이브러리tkinter설치 불필요. 다만 위젯 종류가 적고 기본 외관이 낡았습니다
Qt 바인딩PySide6, PyQt6성숙한 위젯 셋, 네이티브에 가까운 외관, 상업 소프트웨어 실적 다수
웹 기술 기반Electron 계열, pywebview웹 프론트엔드 재사용 가능. 대신 브라우저 엔진을 함께 배포해 무겁습니다

간단한 내부 도구라면 tkinter로도 충분합니다. 그러나 위젯이 다양해지고 화면이 커질수록 tkinter는 손이 많이 가고, 웹 기반은 “메모장 수준의 앱이 수백 MB"가 되는 무게 문제가 따라옵니다. 그 사이에서 네이티브 수준의 성능과 풍부한 위젯을 파이썬 문법 그대로 쓰는 선택지가 Qt 바인딩이고, 이 시리즈는 그중 PySide6를 사용합니다.

PySide6와 PyQt6 — 같은 Qt, 다른 라이선스 #

Qt를 파이썬에서 쓰는 바인딩은 두 개가 공존합니다. 이름이 비슷해 혼란스럽지만, API는 거의 같고 결정적 차이는 누가 만들고 어떤 라이선스로 배포하는가입니다.

구분PySide6PyQt6
제작 주체Qt Group (Qt 공식)Riverbank Computing (서드파티)
라이선스LGPL v3 (상용 앱 무료 배포 가능)GPL v3 또는 유료 상용 라이선스
공식 명칭Qt for PythonPyQt
API 차이Signal, Slot 표기 등 미세한 차이pyqtSignal, pyqtSlot 표기

핵심은 라이선스입니다. LGPL인 PySide6는 소스 코드를 공개하지 않는 상용 앱을 무료로 만들어 팔 수 있지만, GPL인 PyQt6로 같은 일을 하려면 상용 라이선스를 구매해야 합니다. 학습 자료를 검색하면 PyQt 글이 더 많이 나오지만 API가 거의 같아 상호 참고가 가능하고, 새로 시작한다면 공식 지원과 라이선스 부담이 없는 PySide6가 무난한 선택입니다.

노트
PySide6의 6은 Qt 6 기반이라는 뜻입니다. 이 시리즈는 PySide6 6.11(Qt 6.11) 기준이며 Python 3.10 이상이 필요합니다. 검색 중에 만나는 PySide2(Qt 5 기반) 자료는 import 경로와 일부 API가 다르므로 버전을 확인하고 읽기 바랍니다.

설치 #

프로젝트 디렉터리를 만들고 PySide6를 설치합니다. 모던 파이썬 트랙에서 쓴 uv를 그대로 사용합니다.

uv 로 설치
uv init todo-app
cd todo-app
uv add pyside6
pip 를 쓴다면
pip install pyside6

설치가 끝나면 수백 개의 Qt 모듈이 함께 들어옵니다. 이 시리즈에서 주로 쓰는 것은 위젯이 모인 QtWidgets, 시그널과 타이머 같은 코어 기능의 QtCore 두 모듈입니다.

첫 창 띄우기 #

바로 창을 하나 띄워 보겠습니다. 20줄이면 됩니다.

main.py — 첫 창
import sys

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("첫 PySide6 앱")
        self.resize(400, 300)

        button = QPushButton("클릭해 보세요")
        self.setCentralWidget(button)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
실행
uv run python main.py

버튼 하나가 꽉 채운 창이 뜨면 성공입니다. 짧은 코드지만 구조가 이 시리즈 전체의 뼈대이므로 한 줄씩 확인해 두겠습니다.

  • QApplication — 앱 전체를 관리하는 객체입니다. 어떤 위젯보다 먼저, 프로그램당 정확히 하나만 만듭니다.
  • QMainWindow — 메뉴 바, 상태 바, 중앙 위젯 영역을 갖춘 최상위 창입니다. 이를 상속한 클래스에 화면 구성을 담는 방식이 표준 패턴입니다.
  • setCentralWidget — 창의 중앙 영역에 위젯을 배치합니다. 지금은 버튼 하나지만, 다음 글부터는 레이아웃으로 조립한 위젯 묶음이 들어갑니다.
  • window.show() — 창은 만들었다고 표시되지 않습니다. show를 호출해야 화면에 나타납니다.

app.exec() — 이벤트 루프의 의미 #

마지막 줄의 app.exec()가 GUI 프로그램과 스크립트의 갈림길입니다. 지금까지의 파이썬 스크립트는 위에서 아래로 실행하고 끝나면 종료했습니다. 그런데 GUI 앱은 사용자가 언제 버튼을 누를지, 언제 창을 닫을지 알 수 없으므로 끝나지 않고 기다리는 구조가 필요합니다.

app.exec()이벤트 루프를 시작합니다. 마우스 클릭, 키보드 입력, 창 크기 변경 같은 이벤트가 들어올 때마다 해당 위젯에 전달하고, 다시 다음 이벤트를 기다리는 무한 반복입니다. 창을 닫으면 루프가 종료 코드를 반환하며 끝나고, sys.exit()가 그 코드를 운영체제에 넘겨 줍니다.

이 구조에서 한 가지 규칙이 따라 나옵니다. 이벤트 루프를 오래 막으면 앱 전체가 멈춥니다. 버튼 클릭에 연결한 함수가 10초 걸리는 계산을 하면 그동안 화면 갱신도 클릭 처리도 되지 않습니다. 이 문제와 해법은 #6에서 스레드를 다루며 정면으로 확인합니다.

Qt에는 위젯 외에도 네트워크(QtNetwork), 멀티미디어(QtMultimedia), 2D 그래픽스(QtGraphics) 등 응용 프레임워크 수준의 모듈이 포함되어 있습니다. 이 시리즈는 데스크톱 앱의 중심인 위젯과 코어에 집중하지만, 앱이 커져도 프레임워크를 갈아탈 필요가 없다는 점이 Qt의 장점입니다.

마무리 #

이번 글의 핵심은 세 가지입니다.

  • 파이썬 GUI 선택지 중 PySide6는 Qt 공식 바인딩이며, LGPL 라이선스라 상용 앱까지 무료로 만들 수 있습니다.
  • GUI 앱의 표준 뼈대는 QApplication 하나, QMainWindow 상속 클래스, show 호출, 그리고 app.exec()입니다.
  • app.exec()는 이벤트를 기다리며 분배하는 이벤트 루프를 시작하고, 이 루프를 막으면 앱이 멈춥니다.

다음 글인 “PySide6로 데스크톱 앱 만들기 #2 위젯과 레이아웃 — 화면을 조립하는 법"에서는 버튼 하나짜리 창을 넘어, 입력창과 목록과 버튼을 레이아웃으로 조립해 할 일 앱의 화면 뼈대를 세우겠습니다. 이 앱은 시리즈 내내 확장해 나갈 실습 재료입니다.

X