개요
오늘은 여러 개의 QWidget
창을 생성하고,
버튼을 눌렀을 때 특정 QWidget
창을 열리며 로직이 수행되는 코드를 작성해보려고 합니다.
이 코드는 메인 창에서 로그인 창으로 이동
버튼을 클릭하면 로그인 창이 열리고,
새롭게 열린 로그인 창에서 로그인
버튼을 클릭하면 로그인 진행 상황을 보여주는 창이 표시됩니다.
또한 백그라운드에서 로그인 작업을 처리하는 과정을 포함하고 있어요!
작동 영상
이해하기 쉽도록 어떻게 동작하는지 간단하게 움짤 파일로 보여드릴게요.
전체 코드 구조
먼저, 코드의 전체 구조를 살펴볼게요.
제가 구현할 애플리케이션은 네 개의 주요 클래스로 구성되어 있어요.
- 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)
역할
LoginWorker
는QThread
를 상속받아 로그인 작업을 백그라운드에서 실행하는 클래스입니다. 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가 멈추지 않도록 백그라운드 작업을 처리하고, 시그널과 슬롯으로 클래스간 통신을 구현해봤습니다.
실제로는 LoginWorker
의 run
메소드에 서버 통신 로직을 추가하여 원하는 동작의 프로그램으로 천천히 구현해가면 되겠죠?