
Qt는 C++를 주 언어로 사용하는 GUI(Graphic User Interface) 프레임워크이다. '큐트'라고 읽으며, C++와 QML이라는 자체 스크립트 언어를 기반으로 한다. 플랫폼에 독립적인 GUI를 위한 추상화를 제공한다. 또한 네트워킹, 스레드, 정규 표현식, SQL, SVG 등 다양하고 강력한 기능을 제공한다.
PyQt는 윈도우, 유닉스, 리눅스, 맥, iOS 및 안드로이드와 호환된다.
프로젝트 개요 :
OS : macOS
작업환경 : VSC(Visual Studio Code)
프레임워크 : PyQt6(파이썬 3.6.1이상 필요)
python -m venv venv
source venv/bin/activate
python -m pip install pyqt6
혹은
python3 -m venv venv
source venv/bin/activate
python3 -m pip install pyqt6

#hello.py
import sys #내장 모듈 'exit()'함수 사용하기위해 호출
#1. 이들을 사용하여 GUI 애플리케이션을 만들고 관리
from PyQt6.QtWidgets import QApplication, QLabel, QWidget
#2. 'QApplication'클래스의 인스턴스를 생성하여 애플리케이션 객체 생성
app = QApplication([])
#3. 애플리케이션 GUI 생성
window = QWidget()
window.setWindowTitle("PyQt App") #애플리케이션의 창 제목 설정
window.setGeometry(100, 100, 280, 80) #애플리케이션의 창의 크기와 화면 위치 정의(x좌표, y좌표, 너비, 높이)
helloMsg = QLabel("<h1>Hello, World</h1>", parent=window) #QLabel 객체는 HTML 형식의 텍스트 표시
helloMsg.move(60, 15) #'helloMsg'를 창의 좌표 (60, 15)에 배치
#4. 애플리케이션 GUI 보이기
window.show()
#5. 이벤트 루프 실행
sys.exit(app.exec())
(venv) yeryeongseo@seoyelyeong-ui-MacBookPro pyqt % python3 hello.py

이제 그리드 레이아웃을 사용하는 간단한 예제를 해보좌
# g_layout.py
"""Grid layout example."""
import sys
from PyQt6.QtWidgets import (QApplication, QGridLayout, QPushButton, QWidget,)
# PyQt 애플리케이션 생성
app = QApplication([])
# 윈도우 생성 및 제목 생성
window = QWidget()
window.setWindowTitle("QGridLayout")
# 그리드 레이아웃 생성
layout = QGridLayout()
#버튼 위젯 그리드 레이아웃에 추가
# .addWidget()메소드에 전달하는 두번째, 세번째 인수는 각 위젯의 그리드 내 위치 정의
layout.addWidget(QPushButton("Button (0, 0)"), 0, 0)
layout.addWidget(QPushButton("Button (0, 1)"), 0, 1)
layout.addWidget(QPushButton("Button (0, 2)"), 0, 2)
layout.addWidget(QPushButton("Button (1, 0)"), 1, 0)
layout.addWidget(QPushButton("Button (1, 1)"), 1, 1)
layout.addWidget(QPushButton("Button (1, 2)"), 1, 2)
layout.addWidget(QPushButton("Button (2, 0)"), 2, 0)
layout.addWidget(
QPushButton("Button (2, 1) + 2 Columns Span"), 2, 1, 1, 2
)
#윈도우에 레이아웃 설정
window.setLayout(layout)
#윈도우 표시
window.show()
#애플리케이션 이벤트 루프 실행 및 종료
sys.exit(app.exec())

이제 QFormLayout 객체를 사용하여 위젯을 배열하는 애플리케이션을 생성해본다.
# f_layout.py
"""Form layout example."""
import sys
from PyQt6.QtWidgets import (
QApplication,
QFormLayout,
QLineEdit,
QWidget,
)
app = QApplication([])
window = QWidget()
window.setWindowTitle("QFormLayout")
# '.addRow()'라는 메소드를 사용하여 두 개의 위젯이 포함된 행을 레이아웃에 추가
# '.addRow()'의 첫 번째 인수는 라벨 또는 문자열이어야함.
# 두 번째 인수는 사용자가 데이터를 입력/편집 할 수 있는 어떤 위젯이던 무관.
# 이 예제에서는 QLineEdit() 사용
layout = QFormLayout()
layout.addRow("이름:", QLineEdit())
layout.addRow("나이:", QLineEdit())
layout.addRow("직업:", QLineEdit())
layout.addRow("취미:", QLineEdit())
window.setLayout(layout)
window.show()
sys.exit(app.exec())

QDialog 클래스를 사용하여 대화 상자 스타일의 애플리케이션을 만들어보자.
# dialog.py
"""대화형 애플리케이션"""
import sys
from PyQt6.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QFormLayout,
QLineEdit,
QVBoxLayout,
)
class Window(QDialog):
def __init__(self):
super().__init__(parent=None)
#super()을 사용하여 부모클래스의 __init__() 메소드를 호출하여 클래스의 인스턴스 초기화
#이 예제에서는 부모 인수를 None으로 설정. 이 대화상자가 메인 창이 되기 때문
self.setWindowTitle("QDialog")
dialogLayout = QVBoxLayout() #QVBoxLayout 객체를 'dialogLayout'에 할당
formLayout = QFormLayout()
formLayout.addRow("환자명:", QLineEdit())
formLayout.addRow("생년월일:", QLineEdit())
formLayout.addRow("혈액형:", QLineEdit())
formLayout.addRow("몸무게:", QLineEdit())
dialogLayout.addLayout(formLayout)
buttons = QDialogButtonBox()
buttons.setStandardButtons(
QDialogButtonBox.StandardButton.Cancel
| QDialogButtonBox.StandardButton.Ok
)
dialogLayout.addWidget(buttons)
self.setLayout(dialogLayout)
#조건문 안의 들여쓰인 코드가 모듈로 가져와지는것이 아님
if __name__ == "__main__":
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())

대부분의 경우 GUI 애플리케이션은 메인 창 형태로 만들어진다. 메뉴바, 툴바, 상태표시줄 및 위젯이 포함된 유형이다. 사용자의 입력에 따라 여러 대화상자가 필요할수도 있다. 메인 창 형태의 애플리케이션을 만들려면 QMainWindow를 상속해야하는데, 이를 상속한 클래스의 인스턴스는 애플리케이션의 주요 창으로 간주되고, 유일해야한다. QMainWindow는 애플리케이션의 GUI를 빠르게 구축 할 수 있도록 해주는 프레임워크를 제공한다. 이 클래스에는 내장 레이아웃이 있는데 이 중 중심 위젯은 반드시 필요하다. 필요하지 않은 경우, QWidget객체를 사용하여 빈 공간으로 사용 할 수 있다.

메인 창 예제로 연습해보자.
# main_window.py
"""Main window-style application."""
import sys
from PyQt6.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QStatusBar,
QToolBar,
)
class Window(QMainWindow): # QMainWindow를 상속한 Window 클래스 생성
def __init__(self): # 클래스 초기화 메소드 정의
super().__init__(parent=None) # 기본 클래스의 초기화 메소드 호출
self.setWindowTitle("QMainWindow") # 창 제목 설정
self.setCentralWidget(QLabel("I'm the Central Widget")) # 중심 위젯 설정
self._createMenu()
self._createToolBar()
self._createStatusBar() # 비공개 메소드를 호출하여 다양한 GUI 요소 생성
def _createMenu(self):
menu = self.menuBar().addMenu("&Menu")
menu.addAction("&Exit", self.close) # 메인 메뉴 바를 만들고 Menu라는 드랍다운 메뉴 생성
def _createToolBar(self):
tools = QToolBar()
tools.addAction("Exit", self.close)
self.addToolBar(tools) # 툴바 생성. 툴바에는 앱을 종료할 버튼이 포함됨
def _createStatusBar(self):
status = QStatusBar()
status.showMessage("I'm the Status Bar")
self.setStatusBar(status) # 앱의 상태 표시줄 생성
if __name__ == "__main__":
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())

macOS 특성 상 메뉴 옵션의 표시 방식이 다를 수 있다. 애플리케이션을 실행 할 때 'Exit' 혹은 'Quit' 옵션이 메뉴바에서 표시되지않거나 앱의 상단메뉴에서 표시 될 수 있다. 이럴 때는 메인창을 닫거나 'Command + Q'로 종료 할 수 있다...
시그널 자체는 어떠한 동작도 수행하지 않는다. 시그널 작동을 위해서는 슬롯에 연결해야한다. 이는 시그널이 발생 할 때마다 동작을 수행 할 함수 또는 메소드다. 시그널이 슬롯에 연결되어있으면 시그널이 발생 할 때마다 슬롯이 호출된다. 슬롯에 연결되어있지 않는 경우에는 아무 일도 일어나지 않고 시그널이 무시된다. 다음은 시그널과 슬롯의 가장 중요한 특징들이다.
widget.signal.connect(slot_function)
signals_slots.py
import sys
from PyQt6.QtWidgets import (
QApplication,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
)
def greet(): #'greet()'함수를 생성하여 이를 버튼 클릭 시 실행될 슬롯으로 사용
if msgLabel.text(): # 만약 .msgLable의 텍스트가 있는 경우
msgLabel.setText("") # 라벨의 텍스트 삭제
else:
msgLabel.setText("환영합니다!") # 아닐경우 텍스트로 설정
app = QApplication([]) # 애플리케이션 초기화
window = QWidget() # 메인 화면 생성
window.setWindowTitle("Signals and slots")
layout = QVBoxLayout() # 수직 박스 레이아웃 생성. 버튼과 라벨을 수직으로 배치
button = QPushButton("Greet")
button.clicked.connect(greet) # 버튼 클릭 시 'greet()' 함수 출력
layout.addWidget(button) # 버튼을 수직 레이아웃에 추가
msgLabel = QLabel("") # 빈 QLabel 위젯 생성. 버튼이 클릭 될 때 환영메세지 표시
layout.addWidget(msgLabel) # 레이블을 수직 레이아웃에 추가
window.setLayout(layout) # 윈도우에 레이아웃 설정
window.show()
sys.exit(app.exec())


여기까지 PyQt 기본을 정리해보았습니다..
다음 장부터는 계산기를 만들어보아야지