home search
Programming
Python
[PyQt5] PyQt5 Tutorial
2021. 07. 25

해당 글은 [PyQt5 Tutorial - 파이썬으로 만드는 나만의 GUI 프로그램]을 공부한 내용을 바탕으로 하며, 자세한 내용 및 소스코드는 하단 링크를 참조한다.


PyQt5

  1. Qt : 플랫폼에 관계 없이 다양한 기능을 포함하는 C++ 라이브러리 & 개발툴
  2. PyQt5 : Qt5 어플리케이션 프레임워크의 Python 모듈 모음

기초 사용법

창 띄우기 및 기본 구조

  • PyQt5.QtWidgets : 기본적 UI 구성요소 제공 클래스가 포함된 모듈
  • PyQt5 어플리케이션은 어플리케이션 객체를 생성해야 하므로 QApplication 클래스의 변수를 할당
import sys
from PyQt5.QtWidgets import QApplication, QWidget	

class MyApplication(QWidget):

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

    def initUI(self):
        self.setWindowTitle('Application Title')
          #창의 제목표시줄에 나타날 제목
        self.move(300, 300)
          #스크린 상에서 위젯이 나타날 위치(x방향[px], y방향[px])
        self.resize(400, 200)
          #위젯의 크기 (너비[px], 높이[px])
        self.show()
          #위젯을 화면에 띄움

if __name__ == '__main__':
   app = QApplication(sys.argv)
   ex = MyApplication()
   sys.exit(app.exec_())

창을 가운데에 띄우기

  • move() 함수 위치에 지정한 새 함수를 이용해 위치를 설정함
def center(self):
	window_info = self.frameGeometry() #창의 위치와 크기 정보 받음
    center_loc = QDesktopWidget().availableGeometry().center()
      #사용자의 모니터 가운데 위치 파악
    window_info.moveCenter(center_loc) #중심 위치를 지정한 곳으로 이동
    self.move(window_info.topLeft()) #현재 창의 위치를 지정한 곳으로 이동

Main Window(메인 창)

  • 메뉴바, 툴바, 상태바를 갖는 어플리케이션 창
  • QMenuBar, QToolBar, QDockWidget, QStatusBar 위한 고유 레이아웃 가짐
  • 중간 영역에 중심위젯(Central Widget)을 위한 영역 가짐. 모든 위젯이 들어올 수 있음

Layout (레이아웃)

  1. Layout(레이아웃) : 어플리케이션 창에 위젯들을 배치하는 방식. 창을 그리는 함수 부분 이전에 코드 작성함
  2. 절대적 배치(Absolute Positioning) : 위젯의 위치 및 크기를 픽셀 단위로 설정해 배치하는 방법. 창의 크기와 위젯의 크기&위치는 연동되지 않음
    btn = QPushButton('Button', self) #버튼 객체 생성
    btn.move(80, 13) #(가로, 세로) 위치에 버튼 위치시킴
    
  3. 박스 레이아웃(Box Layout)
    • QHBoxLayout, QVBoxLayout 클래스 : 여러 위젯을 수평/수직으로 정렬. 다른 레이아웃 박스를 넣거나 위젯을 배치 가능
    • addStretch() : 필요 공간 확보. stretch factor로 비율 조절
    • 창의 크기를 변화시켜도 같은 자리에 위치
     okButton = QPushButton('OK')
     cancelButton = QPushButton('Cancel')
    
     hbox = QHBoxLayout()	#수평 박스 생성
     hbox.addStretch(1)		#왼쪽에 공간 확보
     hbox.addWidget(okButton) #버튼 넣기
     hbox.addWidget(cancelButton)
     hbox.addStretch(1)		#오른쪽에 공간 확보
    
     vbox = QVBoxLayout()	#수직 박스 생성
     vbox.addStretch(3)		#위쪽에 공간 확보
     vbox.addLayout(hbox)	#수평 박스룰 수직 박스 안에 넣기
     vbox.addStretch(1)		#아래쪽에 공간 확보
    
     self.setLayout(vbox)	#수직박스를 메인 레이아웃으로 설정
    
  4. Grid Layout(그리드 레이아웃)
    • 가장 일반적 레이아웃으로, 위젯 공간을 행과 열로 구분.
    • QGridLayout 클래스 사용
     grid = QGridLayout()	#그리드 레이아웃 생성
     self.setLayout(grid)	#창의 메인 레이아웃으로 설정
    
     grid.addWidget(QLabel('Text Rabel'), 0, 0)	#라벨 객체를 0행 0열에 배치
     grid.addWidget(QLineEdit(), 0, 1)		#텍스트 편집 객체를 0행 1열에 배치
    

Widget (위젯)

QPushButton(버튼), QLabel(텍스트/이미지 라벨), CheckBox(체크박스), QLineEdit(텍스트 편집기), QGroupBox(그룹박스), QSpinBox(정수 선택 및 조절), QTableWidget(표) 등의 위젯이 있어 이를 배치하여 화면을 구성


Signal & Slot (시그널 & 슬롯)

  1. Signal & Slot (시그널 & 슬롯) : 이벤트 처리에 사용되는 매커니즘. 시그널은 이벤트 발생을 알리고 슬롯은 이를 처리함

  2. 연결하기

     lcd = QLCDNumber(self)	#숫자 LCD 스타일로 표시하는 객체
     dial = QDial(self)		#다이얼 객체
    
     dial.valueChanged.connect(lcd.display)
         #QDial 위젯 객체의 시그널에 연결
         # valueChanged() 시그널을 lcd 객체의 display 슬롯에 연결
         # display 슬롯은 숫자를 받아 QLCDNumber 위젯에 표시
    
  3. 이벤트 핸들러(slot)

    • 이미 클래스 내에 만들어진 핸들러 함수 있음
    • 사용자 정의 시그널
     class Communicate(QObject):
         close_app_signal = pyqtSignal() #시그널
    
    
     class MyApplication(QMainWindow):
    
         def __init__(self):
             super().__init__()
             self.initUI()
    
         def initUI(self):
             self.c = Communicate() #시그널 클래스 할당
             self.c.closeApp.connect(self.close) #연결
    
             self.setWindowTitle('Emitting Signal')
             self.setGeometry(300, 300, 300, 200)
             self.show()
    
         def mousePressEvent(self, e):
             self.c.closeApp.emit() #마우스 클릭 시 closeApp 시그널 방출
    

Painting(그림 그리기)

  1. PyQt5.QtGuiQPainter클래스 : 그리기 기능 제공하는 클래스. 위젯의 Paint Event로 동작이 주로 이루어짐

  2. 점 그리기(draw_point)

     import sys
     from PyQt5.QtWidgets import QWidget, QApplication
     from PyQt5.QtGui import QPainter, QPen
     from PyQt5.QtCore import Qt
    
    
     class MyApp(QWidget):
    
         def __init__(self):
             super().__init__()
             self.initUI()
    
         def initUI(self):
             self.setGeometry(300, 300, 400, 300)
             self.setWindowTitle('Points')
             self.show()
    
         def paintEvent(self, e):
             qp = QPainter()		#QPainter 객체 생성
             qp.begin(self)		#QPainter 객체 시작
             self.draw_point(qp)	#그리기 함수
             qp.end()		#그리기 종료
    
         def draw_point(self, qp):
             qp.setPen(QPen(Qt.blue,  8))	#QPen 객체 할당 및 크기 설정
         qp.drawPoint(self.width()/2, self.height()/2)	#위치 설정
         #또는
         # pen = QPen()
         # colors = ['#D83C5F', '#3CD88F', '#AA5CE3', '#29ACF2']
         # for i in range(1000):
         #	pen.setWidth(np.random.randint(1, 15))
         #	pen.setColor(QColor(np.random.choice(colors)))
         #	qp.setPen(pen)
         #	rand_x = 100 * np.random.randn()
         #	rand_y = 100 * np.random.randn()
         #	qp.drawPoint(self.width() / 2 + rand_x, self.height() / 2 + rand_y)
    
    
     if __name__ == '__main__':
         app = QApplication(sys.argv)
         ex = MyApp()
         sys.exit(app.exec_())
    
  3. 직선 그리기 (draw_line)

     def draw_line(self, qp):
         qp.setPen(QPen(Qt.blue, 8))
         #선의 색과 두께 설정 또는 QPen의 Qt.DashLine처럼 선 스타일 설정
         qp.drawLine(30, 230, 200, 50)
         #(첫 점의 x, y, 두번째 점의 x, y)순으로 양 끝점 위치를 정수로 입력
         qp.drawText(30, 90, 'Qt.DashLine') 	#선에 레이블 할당
    

실행파일 만들기

  1. PyInstaller로 Python과 PyQt5로 만든 .py GUI 프로그램을 .exe 파일로 변환 가능
  2. PyInstaller 패키지 설치
    pip install pyinstaller
    
  3. 실행파일 만들기
    • .py 파일이 있는 폴더로 이동 후 명령프롬프트 열어 명령어 입력 : pyinstaller 파일이름.py
    • 폴더 내 dist 폴더로 이동하면 실행파일 존재. 오픈 시 콘솔창이 켜지며 GUI 실행파일 실행
    • 콘솔창 출력되지 않도록 하려면 명령어에 -w 옵션 추가
    • 다른 파일 없이 실행파일 하나만 생성하려면 명령어에 -F 또는 -onefile 옵션 추가

참고자료

PyQt5 Tutorial - 파이썬으로 만드는 나만의 GUI 프로그램

arrow_upward arrow_downward
loading