Profile picture

[PySide6] 다중 QWidget 창 연동 예시

JaehyoJJAng2024년 09월 25일

개요

오늘은 여러 개의 QWidget 창을 생성하고,

버튼을 눌렀을 때 특정 QWidget 창을 열리며 로직이 수행되는 코드를 작성해보려고 합니다.


이 코드는 메인 창에서 로그인 창으로 이동 버튼을 클릭하면 로그인 창이 열리고,

새롭게 열린 로그인 창에서 로그인 버튼을 클릭하면 로그인 진행 상황을 보여주는 창이 표시됩니다.

또한 백그라운드에서 로그인 작업을 처리하는 과정을 포함하고 있어요!


작동 영상

이해하기 쉽도록 어떻게 동작하는지 간단하게 움짤 파일로 보여드릴게요.
Image


전체 코드 구조

먼저, 코드의 전체 구조를 살펴볼게요.

제가 구현할 애플리케이션은 네 개의 주요 클래스로 구성되어 있어요.

  • 1. LoginWorker: 로그인 작업을 백그라운드에서 처리하는 스레드 클래스입니다.
  • 2. LoginProgressUI: 로그인 진행 상황을 보여주는 창이에요.
  • 3. LoginUI: 로그인 입력 창을 구현했어요.
  • 4. MainUI: 애플리케이션의 메인 창이에요.

그리고 .ui는 다음과 같은 구조로 생성되어 있다고 보면 됩니다.

layout.ui
login_window.ui
progress_bar.ui

코드 분석하기

이제 애플리케이션 코드를 분석해볼게요!


1. LoginWorker 클래스

class LoginWorker(QThread):
    login_finished = Signal(bool, dict)

    def __init__(self, id: str, pw: str):
        super().__init__()
        self.id = id
        self.pw = pw

    def run(self) -> None:
        # 로그인 로직
        time.sleep(5)

        # 쿠키
        cookies = {"message": "success"}

        # 로그인 완료
        self.login_finished.emit(True, cookies)

역할

  • LoginWorkerQThread를 상속받아 로그인 작업을 백그라운드에서 실행하는 클래스입니다. UI가 멈추지 않도록 별도의 스레드에서 작업을 처리합니다.

2. LoginProgressUI 클래스

class LoginProgressUI(QWidget, progress_ui):
    login_successful = Signal(dict)
    log = Signal(str)

    def __init__(self, id: str, pw: str):
        super().__init__()
        self.setupUi(self)

        # "물 흐르듯이" 애니메이션 적용
        self.progress_bar.setRange(0, 0)

        # 스레드 생성
        self.login_worker = LoginWorker(id=id, pw=pw)
        self.login_worker.login_finished.connect(self.update_login_finished)
        self.login_worker.start()

    def update_login_finished(self, success: bool, finished: dict) -> None:
        # 일반 진행바로 복귀
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(100)

        if success:
            self.login_successful.emit(finished)
            self.log.emit("로그인에 성공했습니다!")
            self.progress_label.setText("로그인에 성공했습니다")
        else:
            self.login_successful.emit({})
            self.log.emit("로그인에 실패했습니다!")
            self.progress_label.setText("로그인에 실패했습니다")

        # Prgress 창 닫기
        self.close()

역할

  • LoginProgressUI는 로그인 진행 상황을 시각적으로 보여주는 창입니다. 진행 바를 통해 작업 상태를 표시합니다.

3. LoginUI 클래스

class LoginUI(QWidget, login_ui):
    log = Signal(str)
    cookies = Signal(dict)

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # 시그널 연결
        self.login_button.clicked.connect(self.login)

    def login(self) -> None:
        # 로그인 스레드 생성
        self.login_progress = LoginProgressUI(id="test", pw="test")
        self.login_progress.login_successful.connect(self.login_successful)
        self.login_progress.log.connect(self.login_log)
        self.login_progress.show()

    def login_successful(self, cookies: dict) -> None:
        if cookies:
            self.cookies.emit(cookies)
        else:
            self.cookies.emit({})

        # 로그인 창 닫기
        self.close()

    def login_log(self, log: str) -> None:
        self.log.emit(log)

역할

  • LoginUI는 사용자가 로그인 버튼을 클릭할 수 있는 로그인 창입니다.

4. MainUI 클래스

class MainUI(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # 시그널 연결
        self.load_login_window_button.clicked.connect(self.login)

    def login(self) -> None:
        self.login_dialog = LoginUI()
        self.login_dialog.cookies.connect(self.update_login_cookies)
        self.login_dialog.log.connect(self.update_login_log)
        self.login_dialog.show()

    def update_login_cookies(self, cookies: dict) -> None:
        self.cookies = cookies

    def update_login_log(self, log: str) -> None:
        print(log)

역할

  • MainUI는 애플리케이션의 메인 창으로, 로그인 버튼을 제공합니다.

마무리

다중 Qwidget 창을 생성하고, 버튼 클릭 시 로그인 로직을 수행하는 프로그램을 간단하게 구현해봤습니다!

QThread를 사용해 UI가 멈추지 않도록 백그라운드 작업을 처리하고, 시그널과 슬롯으로 클래스간 통신을 구현해봤습니다.

실제로는 LoginWorkerrun 메소드에 서버 통신 로직을 추가하여 원하는 동작의 프로그램으로 천천히 구현해가면 되겠죠?


Loading script...