파이썬으로 프로그램을 만들다보면
그냥 콘솔 프로그램만으로도
매우 다양한 앱을 구현할 수 있습니다만
배포용 앱을 만들기 위해서는
컴퓨터를 모르는 사람도
쉽게 사용할 수 있도록
GUI 를 만들어 줘야 하는데요.
GUI를 처음부터 만들 수도 있겠지만
그건 시스템 프로그래밍이 필요해서
쉽지 않은 부분이고요.
애플리케이션 개발자들은 GUI 모듈이라는
인터페이스(interace)를 사용합니다.
GUI는 콘솔앱과 달라서 이벤트 처리라는
틀안에서 프로그래밍을 해야 합니다.
GUI 프레임워크라고 부르는 것은
Framework 의 뜻이 틀이라는 건데요.
유저가 그래픽적으로 컨트롤 하는 부분은
그 Framework - 틀에 맞춰서 작성해야 합니다.
파이썬 GUI Framework 에는 많은 옵션이 있습니다.
첫번째는 tkinter (tool kit interface 의 약자)로
파이썬의 기본 패키지에 GUI로 등록되 있습니다.
tkinter 는 tcl/tk라는 좀 오래된 오픈 소스 프로젝트의
Wrapper - 래퍼(다른 언어에서 재사용 하는 것) 로써
GUI 프로그래밍을 처음 학습하는 사람들이나
또는 빠른 속도로 프로토타입을 만들 때도 유용합니다.
좀 허접하다고 말할 수도 있겠지만
쉽고 간단한 프레임워크로
많은 사람들에게 사랑을 받고 있습니다.
tkinter 말고는 여러가지가 있습니다.
pyGTK, wxPython, Kivy, PyGUI 등
역시 다양한 오픈소스 프로젝트를
가진 파이썬 답게 선택할 수 있는 옵션이 많은데요.
이 포스팅에서 시리즈로 집중하려고 하는 것은
PyQt5 입니다. 이는 C++ 용 Qt의 파이썬 바인딩입니다.
(바인딩 -binding C++ 네이티브 코드를
파이썬에서 사용할 수 있도록 해주는 API)
파이썬의 많은 GUI 프로젝트 중에서
수천개의 위젯 클래스와
PyQpenQL같은 그래픽 인터페이스도 제공하는
PyQt5가 가장 강력하다고 볼 수 있습니다.
단 PyQt5 상업용 개발을 위한 라이센스는
riverbank computing에 별도로 납부해야 합니다.
(1년간 개발자 당 미화 550달러 수준)
상업용 앱을 개발하려는 분들은
개발사의 라이센스 정책을 잘 읽어 보시길 바랍니다.
오픈소스 프로젝트라고
모두가 공짜는 아닙니다.
개발사가 업데이트와 기술지원을 하고 있다면
상업용 개발자들의 경우 돈을 내야 합니다.
(자바도 오라클 API는 돈을 내야합니다)
PyQt5같은 바인딩이 좋은 것은
속도가 빠른 C++ 코드를 실행시키는 부분입니다.
파이썬은 뭐 C++에 비하면
엄청 느린 로직을 가지고 있습니다.
실행시간을 중시하는 스크립트 언어의
특성이라고 할 수 있는데요.
기계어 코드를 컴파일 하지 않고
즉석에서 기계어를 번역 하다보니
아무래도 C++ 같은 정적인 언어들 보다
느려질 수밖에 없는데요.
모든 것을 파이썬 코드로 바꾸지 않고
이미 컴파일되있는 C++ 코드와 라이브러리를
실행시키는 방식으로 속도 문제를 보완할 수 있습니다.
실제 연산이 많이 필요한 AI나 빅데이터 처리 등은
파이썬 코드가 아니라 C++을 컴파일한
기계어를 사용하는 경우가 많습니다.
이것은 매우 쉬운 파이썬 코드로
복잡한 C++ 코드를 돌리는 것과 같습니다.
위에서 콘트롤은 파이썬으로 쉽게 하고
아래의 동작들은 C++이 효율적으로 한다.
각 언어의 장점만 사용하는 하이브리드(짬뽕) 개념입니다.
그럼 PyQt5의 성능과 장점을 알았으니
바로 예제를 시작해 보겠습니다.
외부 패키지이므로 pip 로 설치합니다.
pip install pyqt5
PyQt5에서는 QtWidget 이나 QMainWindow 등을
사용해서 윈도우 창을 만들 수 있습니다.
많은 프로젝트들이 시간에 걸쳐서
진화하다 보면 어떤 클래스들은
지원이 중단되기도 하고(deprecated)
새로운 클래스가 도입되기도 합니다.
따라서 윈도우창 하나 만드는데도
여러가지 클래스를 사용하도록
허용하는 경우도 있습니다.
처음 학습시에는 표준적인 방법으로
GUI 를 만들다가 어느정도 익숙해지면
본인의 입맛에 맞는 스타일로 GUI를 설계하면 됩니다.
여기서는 QtWidgets 인스턴스를 사용합니다.
위짓(Widgets) 이라는 것은 눈에 보이는
콘트롤 요소를 말합니다.
예를 들어 윈도우 버튼, 레이블, 체크박스 등은
모두 위짓입니다.
윈도우의 프레임도 위짓입니다.
이들은 대부분 비슷한 속성을 공유하므로
비슷한 그룹의 요소들이 상속관계를 가집니다.
하다보면 자꾸 반복된다는 것을 느낄 겁니다.
다음은 PyQt5 윈도우 창을 만드는 코드입니다.
from PyQt5 import QtWidgets
import sys
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myWin = QtWidgets.QWidget()
myWin.show()
app.exec_()
위의 코드는 가장 기본적인 구조를 보여줍니다.
일단 여기가 기본 시작점으로 생각하면 됩니다.
이 형식을 지키면서 앱을 만들 겁니다.
QWidget은 아무 설정도 하지 않은
기본 윈도우를 생성하는 클래스입니다.
QApplication 인스턴스는 하나의 윈도우를
생성합니다.
exec_() 를 실행시키면 윈도우는
윈도우 루프라는 상태에 들어가는데
여기서부터 이벤트 처리가 가능합니다.
QWidget은 다른 컨트롤 요소들의 base로
QWidget의 메소드들을 상속 받습니다.
(버튼, 레이블 같은 것도 작은 윈도우 객체로 볼 수 있음)
QWidget Class | Qt Widgets 5.15.4
윈도우 프로그래밍은 객체지향프로그래밍에
적합합니다.
GUI 의 콘트롤 요소들은 객체이며
이벤트 루프에서 이벤트 자체도
객체입니다.
그래서 절차형 프로그래밍 방식이 아니라
객체지향 프로그래밍 코드로 바꾸어 보겠습니다.
from PyQt5 import QtWidgets
import sys
class myFirstWindow(QtWidgets.QWidget):
def __init__(self):
super(myFirstWindow,self).__init__()
self.setGeometry(300, 300, 320, 240)
self.setWindowTitle('My First Window')
self.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myWin = myFirstWindow()
app.exec_()
우선 myFirstWindow 라는 클래스에
QWidget 을 상속받아서
그 안에서 필요한 모든 초기화를 시켜줍니다.
속성들도 바꿔보겠습니다. ssetGeometry 처럼
자기 스스로 설명하는 메소드입니다.
요런 코드들은 프로그램의 로직이라기 보다는
설정값에 가깝습니다.
GUI 프로그래밍을 하면서
여러가지의 설정을 하게되는데요.
결국 윈도우 창이란 것은 틀이란게
정해져 있습니다.
PC나 스마트폰이나 맥북이나
화면 사이즈나 터치등에 각 시스템의
특성에 따른 설정값이 존재할 뿐입니다.
이벤트 처리에 관해서는
거의 정해져 있으니까요.
(마우스 버튼클릭, 터치, 드래그 등)
PyQt5나 tkinter 나 비슷합니다.
JavaFX나 kivy 처럼 xml 을 사용하는 방식을 보면
요새는 약간 웹개발과 닮은 느낌의 GUI도 있는데요.
레이아웃, 디자인 이런 것은
거의 비슷하다고 보면 됩니다.
PyQt5의 레이블은 QLabel 이며
버튼은 QPushButton 클래스입니다.
객체 지향 방식에 따라 클래스로 정의해보겠습니다.
버튼과 레이블 클래스를 상속받아서 사용합니다.
둘다 텍스트라는 특성이 있으므로
문자열과 그 요소를 넣을 프레임(윈도우)만
있으면 생성할 수 있습니다.
from PyQt5 import QtWidgets
import sys
class myFirstWindow(QtWidgets.QWidget):
def __init__(self):
super(myFirstWindow, self).__init__()
self.btn2 = basicButton(self, "my Button")
self.label1 = basicLabel(self, "my Label")
self.setup()
def setup(self):
self.setGeometry(300, 300, 320, 240)
self.setWindowTitle('My First Window')
self.setToolTip("This is the PyQt5")
self.btn2.move(100, 100)
self.show()
class basicButton(QtWidgets.QPushButton):
def __init__(self, frame, text):
QtWidgets.QPushButton.__init__(self, frame)
self.setText(text)
self.move(50, 50)
class basicLabel(QtWidgets.QLabel):
def __init__(self, frame, text):
QtWidgets.QLabel.__init__(self, frame)
self.setText(text)
self.move(20, 20)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myWin = myFirstWindow()
app.exec_()
클래스를 사용하지 않는게
코드의 개수는 줄어들겠지만
이렇게 객체를 생성하면
자신이 만든 객체이므로
잘 잊어버리지 않습니다.
원래 객체 지향 프로그래밍이
코드가 길어집니다.
자바의 경우 뭐 간단한 프로그래밍
하나 작성하는데도 코드가 엄청 길죠.
이는 프로그래머마다 호불호가 있을 수 있습니다.
보통적으로는 코드의 양이 길어질때
위력을 발휘하는게 객체지향 코드입니다.
파이썬으로 간단한 프로그램을 만들더라도
코드 1000줄 정도는 사용한다고 생각하면
그리 나쁜 방법은 아닙니다.
어떤 사람들은 객체지향 코드가 쓸데없이
길어지는게 불편하다는 사람도 있지만
어쨋든 현재까지 가장 검증된 방식이고
또 파이썬은 자바 등에 비하면
코드가 거의 간단하기 때문에
가급적 클래스 사용법에 익숙해지는게 좋습니다.
(파이썬도 객체지향 프로그래밍 언어입니다)
PyQt5의 윈도우 창을 생성하고
레이블과 버튼까지 생성해봤습니다.
다음 포스팅에서는 버튼을 클릭했을 때
이벤트를 처리하는 방법 등에 대해서 알아보겠습니다.