개요
이번 게시글에서는 PySide6와 Qt Designer를 이용하여
여러 개의 윈도우(메인 창, 서브 창1, 서브 창2)를 단계적으로 띄우는 프로그램을 구현해보려고 한다!
목표
- 1. 메인 윈도우가 프로그램 실행 시, 모니터 왼쪽, 수직 중앙에 위치하도록 함.
- 2. 서브 창1(SubWindow1)을 메인 윈도우 오른쪽에 열기
- 3. 서브 창2(SubWindow2)는 서브 창1의 오른쪽에 열기
- 4. 프로그램 종료 시(메인 윈도우 닫을 때), 열려 있는 모든 서브 창도 자동으로 닫혀야 함.
개발 환경 준비
1. Qt Designer에서 .ui
파일을 만든 뒤 pyside6-uic
또는 pyuic
을 사용하여 .py
파일로 변환시키기
2. 디렉터리 구조 예시는 다음과 같다.
my_project/
├─ main.py
├─ main_layout/
│ ├─ main_ui.py # QtDesigner로부터 변환된 메인 UI
├─ sub1_layout/
│ ├─ sub_window1_ui.py # QtDesigner로부터 변환된 창1 UI
├─ sub2_layout/
│ ├─ sub_window2_ui.py # QtDesigner로부터 변환된 창2 UI
코드 구현 예시
핵심 포인트!
- 메인 윈도우, 서브 창1, 서브 창2 모두
QWidget
상속 - 서브 창을 열 때,
parent=상위객체
로 설정하여 부모-자식 관계 를 만들도록 함.- 이렇게 해야 메인 창이 닫힐 때 서브 창들이 자동으로 정리됨.
- 각 창의 위치는
move(x,y
) 메소드를 통해 자유롭게 조정하도록 함.
import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QScreen
# QtDesigner로부터 변환된 UI 모듈 임포트
from main_layout.main_ui import Ui_Form as MainUI
from sub1_layout.sub_window1_ui import Ui_Form as Sub1UI
from sub2_layout.sub_window2_ui import Ui_Form as Sub2UI
class MainAPP(QWidget, MainUI):
"""메인 윈도우 클래스"""
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
# 1) 메인 윈도우 크기 지정
self.resize(400, 300)
# 2) 메인 윈도우 위치를 모니터 '왼쪽 중앙'에 배치
# (참고) Qt에서 스크린 정보를 가져오려면 QScreen 사용
screen_geo = QApplication.primaryScreen().availableGeometry()
screen_width = screen_geo.width()
screen_height = screen_geo.height()
# x 좌표: 왼쪽에서 10px 정도 띄운다
main_x = 10
# y 좌표: 모니터 중앙 (화면 높이 - 윈도우 높이) / 2
main_y = (screen_height - self.height()) // 2
self.move(main_x, main_y)
# 3) 창1에 대한 참조 변수
self.sub_window1 = None
# 4) 메인 UI의 QToolButton 클릭 시 창1 열기
self.openSub1.clicked.connect(self.show_subwindow1)
def show_subwindow1(self):
"""메인 윈도우 오른쪽에 창1을 띄운다."""
# 창1이 없거나, 이미 닫혀있다면 새로 생성
if self.sub_window1 is None or not self.sub_window1.isVisible():
self.sub_window1 = SubWindow1(self) # parent=self
self.sub_window1.show()
# 메인 윈도우 오른쪽 + 10px 정도 띄운 위치
main_geo = self.geometry()
sub1_x = main_geo.x() + main_geo.width() + 10
sub1_y = main_geo.y()
self.sub_window1.move(sub1_x, sub1_y)
else:
# 이미 창1이 떠 있다면 최상위로 올려주기
self.sub_window1.raise_()
self.sub_window1.activateWindow()
class SubWindow1(QWidget, Sub1UI):
"""서브 창1 클래스: 여러 버튼이 있고, 클릭 시 창2를 띄움"""
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
# 창2를 가리킬 참조 변수
self.sub_window2 = None
# 예시: sub_window1_ui.py 안에 buttonA, buttonB 버튼이 있다고 가정
self.buttonA.clicked.connect(lambda: self.show_subwindow2("A"))
self.buttonB.clicked.connect(lambda: self.show_subwindow2("B"))
def show_subwindow2(self, button_type):
"""창1의 특정 버튼 클릭 시 창2 띄우기
이미 창2가 열려 있다면 닫고 새로 연다.
"""
# 기존 창2가 열려 있다면 닫는다
if self.sub_window2 is not None:
self.sub_window2.close()
self.sub_window2 = None
# 창2 생성 (부모 = self)
self.sub_window2 = SubWindow2(button_type, self)
self.sub_window2.show()
# 창1 오른쪽에 창2 배치
geo = self.geometry()
sub2_x = geo.x() + geo.width() + 10
sub2_y = geo.y()
self.sub_window2.move(sub2_x, sub2_y)
class SubWindow2(QWidget, Sub2UI):
"""서브 창2 클래스: 창1에서 클릭된 버튼에 따라 동작 달라짐"""
def __init__(self, button_type, parent=None):
super().__init__(parent)
self.setupUi(self)
# button_type 이 A냐 B냐에 따라 타이틀(or 기능) 분기 처리
if button_type == "A":
self.update_button_type_A()
elif button_type == "B":
self.update_button_type_B()
def update_button_type_A(self) -> None:
self.setWindowTitle("창2 - A 버전")
def update_button_type_B(self) -> None:
self.setWindowTitle("창2 - B 버전")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainAPP()
window.show()
sys.exit(app.exec())