PyQT-1(code)
1. PyQT
어떤 프로그램을 CLI로 개발하는 것, GUI로 개발하는 것은 엄청난 차이다. 상대방에게.
사실 GUI로 만드는것은 개발자의 입장에서는 굉장히 번거로운데,
잘모르는사람의 입장에서는 GUI로 만들어져있으면 버튼의 나열이라도, 우와-하게된다.
그래서 기왕주는거 더 어깨 으쓱할 수 있게 허접한 형태로라도 GUI로 주자.
PyQT는 클래스가 1000여개가 넘는 범용 프레임워크다. 그래서 모두 설명할 수는 없고, 이런거구나 하는 정도만 확인한뒤 직접 찾아보면서 하며된다. C나 C++로 이루어진 라이브러리를 임포트 해서 사용할 수 있기 때문에 한번 알아놓으면 굉장히 좋다.
2. 준비
(a)개별적인 개발환경을 위해 anaconda 설치
https://www.anaconda.com/products/individual
Individual Edition | Anaconda
🐍 Open Source Anaconda Individual Edition is the world’s most popular Python distribution platform with over 20 million users worldwide. You can trust in our long-term commitment to supporting the Anaconda open-source ecosystem, the platform of choice for
www.anaconda.com
(별로 어렵지 않으니 아나콘다를 잘모르는 사람은 다른 블로그를 잠깐보고 오면 된다. 그리고 설치가 귀찮다면 로컬에 해도 상관없다.)
(b)anaconda 프로젝트 만들기
python 3.5로는 에러가 있는것 같습니다. 3.6 설치 추천 드립니다.
(c). 프로젝트관련 폴더 준비
(d). Text Editor 실행.
모든 설명은 나의 환경 중심이다.. Anaconda와 visual studio code연동이 가능하니 실행해준다.
(설치안된사람은 설치를 추천한다. VS Code는 다른 코드 작성에도 유용하다.)
VS Code가 싫은사람은 atom을 이용할 수 도 있다. atom의 경우 [그림3]의 상황에서 atom이라고 입력하면 연동된다.
VSCode에서 Open Folder로 '4'에서 만든 폴더를 불러오고,
터미널을 열어서 앞서 만든 conda project와 연동해주면 개발 준비 끝
3. 기본
import sys
from PyQt5.QtWidgets import *
if __name__ == "__main__":
#1. 캔버스를 만들자
app = QApplication(sys.argv)
#2. 캔버스에 붙일 스티커 하나를 만들자
label = QLabel("Hello World !")
#3. 스티커를 캔버스에 붙이자
label.show()
#4. 캔버스를 눈에 보이게 하자
app.exec_()
print("END!")
코드의 주석에서 말하는 캔버스는 Main GUI로 App 자체라 생각하면 된다.
QApplication은 PyQt5.Qwidgets.QApplication()으로, sys.argv(파일실행 경로)를 초기화 변수로 넘겨주고 있다.
여기서 #3의 .show()까지하면 캔버스가 안보이기때문에 label이 안나타난다.
print("END!")는 언제출력될까.
exec_()가 실행되면 exec_()안에서 무한루프로 사용자의 입력을 계속 기다리고 그에 대한 이벤트 처리를 하기 때문에
닫기 버튼을 눌러야만 print("END!")가 실행될 수 있다.
다음 예제를 살펴보자
if __name__ == "__main__":
app = QApplication(sys.argv)
window = exampleForm()
window.show()
app.exec_()
첫번째 예제 코드와 달라진 부분은 window = exampleForm() 부분이다.
텍스트하나 찍어낼게 아니라 좀더 복잡한 GUI를 만들어야하니 클래스로 빼낸것이다.
클래스의 코드를 보면,
class exampleForm(QMainWindow):
def __init__(self):
super().__init__()
self.setupUI()
def setupUI(self):
self.setWindowTitle("PY PY PY")
self.setGeometry(800,400, 900,500)
btn_1 = QPushButton("button1", self)
btn_2 = QPushButton("button2", self)
btn_3 = QPushButton("button3", self)
btn_1.move(20,20)
btn_2.move(20,60)
btn_3.move(20,100)
btn_1.clicked.connect(self.btn_1_clicked)
btn_2.clicked.connect(self.btn_2_clicked)
btn_3.clicked.connect(QCoreApplication.instance().quit)
def btn_1_clicked(self):
QMessageBox.about(self, "message", "clicked")
def btn_2_clicked(self):
print("BUTTON CLICKED!")
예제코드인 exampleForm은 QtWidgets 패키지 안에있는 QMainWindow를 상속받는다.
QMainWindow도 Qtwidgets처럼 캔버스(레이아웃) 이지만,
QtWidgets와는 다르게 메뉴바와 상태바 등이 이미 세팅되어 나오는데 이부분은 나중에 살펴 볼 것이다.
코드를 한 부분씩 살펴보자
def __init__(self):
super().__init__()
self.setupUI()
class 생성시 실행되는 생성자이다.
상속받은 부모 클래스의 생성자를 실행시켜주고 같은 클래스 내의 setupUI() 메소드를 실행시킨다.
def setupUI(self):
self.setWindowTitle("PY PY PY")
#800,400 지점에 위치하도록 실행되고 900,500 크기를 가지도록 해라
self.setGeometry(800,400, 900,500)
btn_1 = QPushButton("button1", self)
btn_2 = QPushButton("button2", self)
btn_3 = QPushButton("button3", self)
btn_1.move(20,20)
btn_2.move(20,60)
btn_3.move(20,100)
btn_1.clicked.connect(self.btn_1_clicked)
btn_2.clicked.connect(self.btn_2_clicked)
btn_3.clicked.connect(QCoreApplication.instance().quit)
setWindowsTitle()
- APP의 이름 설정
setGeometry()
- APP이 실행될 위치와 창 크기 설정
QPushButton()
-버튼 생성
btn_#.move()
- 생성한 버튼 위치 설정 (지정하지않으면 0,0 부분에 모든 버튼들이 겹쳐질 것이다)
btn_#.clicked.connect()
- 버튼이 클릭되었을때 어떤 동작을 할지 설정
버튼이 클릭되는걸 APP의 입장에서는 이벤트(시그널) 발생이라고 하는데,
connect() 메소드로 시그널과 이벤트처리함수를 연결시킬 수 있다.
여기서 이벤트를 처리하는 함수를 슬롯이라 부른다.
즉 예제 코드처럼 btn_1.clicked.connect(self.btn_1_clicked)이면,
btn_1 버튼이 클릭되었을때,
클래스 내의 btn_1_clicked라는 슬롯이 호출되어 지정한 동작을 수행할 것이다. (이 경우 메시지박스 생성)
QCoreApplication.instance().quit은 이미 정의된 슬롯으로서 앱을 종료시킨다. (닫기 클릭과 동일)
다음 예제를 살펴보자
이번에는 간단하게 Text Box를 만들어서 입력, 출력 부분을 해볼거다.
이전 예제에서 setupUI() 메소드 코드만 바꾸면된다.
def setupUI(self):
self.setWindowTitle("PY PY PY")
self.setGeometry(800,400, 900,500)
self.statusBar = QStatusBar(self)
self.setStatusBar(self.statusBar)
label_in = QLabel("input", self)
label_in.move(100,100)
label_out = QLabel("output", self)
label_out.move(100,150)
#EditBox
self.editBox = QLineEdit("Please enter anything...", self)
self.editBox.move(150,100)
#TextBox
self.textBox = QtWidgets.QPlainTextEdit(self)#from pyQt import QtWidgets
self.textBox.move(150,150)
label 변수는 self를 안썼는데
editBox과 textBox 앞에 self를 쓴 이유는 다른 메소드에서 참조하기 위해서이다.
뒤에 사용할때 다시 한번 알아보자
결과화면이 뭔가 마음에 안든다.
editBox의 경우 넓이가 더 넓었으면좋겠고
textBox의 경우 더 컸으면 좋겠다.
코드를 아래와같이 수정해보자.
self.editBox = QLineEdit("Please enter anything...", self)
self.editBox.setGeometry(QtCore.QRect(150,100,350,30))#from pyQt import QtCore
self.textBox = QtWidgets.QPlainTextEdit(self)#from pyQt import QtWidgets
self.textBox.setGeometry(QtCore.QRect(100,180,400,200))#x, y, w, h
self.textBox.setReadOnly(True)
이제 훨씬 볼만하다.
self.textBox.stReadOnly(True)로 수정하지 못하고 출력만 할 수있도록 지정할 수 있다.
이제 이벤트를 몇개 만들어 슬롯과 연결해 보자.
def setupUI(self):
self.setWindowTitle("PY PY PY")
self.setGeometry(800,400, 900,500)
self.statusBar = QStatusBar(self)
self.setStatusBar(self.statusBar)
label_in = QLabel("input", self)
label_in.move(100,100)
label_out = QLabel("output", self)
label_out.move(100,150)
self.editBox = QLineEdit("Please enter anything...", self)
self.editBox.setGeometry(QtCore.QRect(150,100,350,30))
self.textBox = QtWidgets.QPlainTextEdit(self)
self.textBox.setGeometry(QtCore.QRect(100,180,400,200))
self.textBox.setReadOnly(True)
self.editBox.textChanged.connect(self.ChangedEditBox)
self.editBox.returnPressed.connect(self.InputEditBox)
def ChangedEditBox(self):
#이렇게 다른 메소드에서 불러오기위해서 self를 입력한 것입니다.
self.statusBar.showMessage(self.editBox.text())
def InputEditBox(self):
self.textBox.appendPlainText(self.editBox.text())
self.editBox.clear()
5-6번째 라인을 보면 statusBar가 추가되었다.
statusBar는 레이아웃 아래쪽에 자리해서 '입력중...'같은 상태를 나타내어줄 수 있다.
여기서는 self.editBox.textChanged.connect(self.ChangedEditBox) 을 통해
사용자가 입력한 값을 그대로 출력 시켜줄 것이다.
또한 self.editBox.returnPressed.connect(self.InputEditBox)을 통해
EditBox에서 사용자가 엔터를 입력하면 textBox에 출력 시켜줄 것이다.
직접실행해보면 아래와같다.
이제 코드부분은 간단하게 끝났다.
레이아웃 디자인을 코드로 하게되면 크기같은것을 지정할때 코드 수정 > 실행을 반족하는데 굉장히 비효율적이다.
때문에 C#이 그러하듯 PYQT 코드는 잘 안쓰고 대부분(거의 모두) 디자이너를 이용하는데
다음 PyQT-2에서 디자이너 사용법을 알아보자.