시그날과 슬롯

PyQt5에서는 이벤트를 시그날/슬롯(Signal/Slot)

메카니즘으로 처리합니다.

 

윈도우 GUI 프로그램은 기본적으로

윈도우 루프라는 무한 루프를 돌고 있습니다.

 

이때 발생하는 사건을 이벤트(Event)라고 하며

이벤트에 대응하는 행동을 액션(action)이라고 합니다.

 

PyQt5 에서는 이벤트를 시그날

행동을 액션이라고 이름 붙였습니다.

 

예를 들어서 마우스로 버튼을 클릭하면

QPushButton.clicked 라는 이벤트가 발생합니다.

이벤트는 외부의 입력에 의해서 발생되는데

운영체제가 마우스가 클릭된 것을 감지하고

어떤 영역에서 클릭되었는지 확인해서

PyQt5 프로그램에 정보를 넘겨줍니다.

 

이를 처리하는 것은 운영체제의 레벨로

앱 개발자들이 알아야 할 것은

어떤 시그날이 발생했냐는 것 입니다.

시그날은 변수의 형태로 전달이 되겠죠.

 

반면 시그날에 대응하는 액션, 슬롯은

함수의 형태입니다.

 

예를 들어 Quit (종료) 버튼을 클릭했다

그러면 종료에 관련한 함수가 실행되는 것 입니다.

 

예제를 통해서 알아보겠습니다.

 

윈도우 창 닫는 예제 - 시그날과 슬롯

 

다음은 윈도우 창을 닫는 예제입니다.

 

Quit 버튼을 클릭했을시에

종료할 것인지 물어보고

Yes 클릭시 종료 No 클릭시 돌아갑니다.

 

QWidget 클래스에서 closeEvent 를 오버라이드합니다.

 

QuitMsg 클래스는 메세지 박스를 사용하고요.

No 와 Yes 버튼을 추가할 수 있습니다.

from PyQt5 import QtWidgets
import sys

class myFirstWindow(QtWidgets.QWidget):
    def __init__(self):
        super(myFirstWindow, self).__init__()
        self.btn3 = QuitBtn(self)
        self.setup()

    def setup(self):
        self.setGeometry(900, 700, 300, 200)
        self.setWindowTitle('My First Window')
        self.setToolTip("This is the PyQt5")

        self.show()

    def closeEvent(self, event):
        reply = QuitMsg().exec_()
        if reply == QtWidgets.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

class QuitMsg(QtWidgets.QMessageBox):
    def __init__(self):
        QtWidgets.QMessageBox.__init__(self)
        self.setText("Want to Quit?")
        self.addButton(self.No)
        self.addButton(self.Yes)

class QuitBtn(QtWidgets.QPushButton):
    def __init__(self, frame):
        QtWidgets.QPushButton.__init__(self,frame)
        self.setText("Quit")
        self.move(100,100)
        # self.clicked.connect(QtWidgets.qApp.quit)
        self.clicked.connect(frame.close)
        self.setToolTip("Close the window")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myWin = myFirstWindow()
    app.exec_()

QuitBtn 은 종료 버튼으로 여기서

잘 볼 것은 self.clicked.connect 입니다.

여기에 버튼을 클릭하면 실행할

함수를 넣습니다.

close 는 QWidget 의 메소드입니다.

close 메소드는 윈도우를 종료합니다.

메소드인데 () 을 넣지 않는 것은

초기화에서 실행시키지 않고

이벤트가 발생했을 때 슬롯 호출시에

종료하기 위해서 입니다.

 

C++ 처럼 해석하면 함수를 실행하지 않고

주소만 주는 것이죠.

필요할 때 사용할 수 있도록

 

PyQt5 윈도우 종료
PyQt5 윈도우 종료

딱히 어려울 것은 없지만

시그날과 슬롯을 연결시킨다는 측면에서

GUI 프로그래밍의 작동 방식을 이해할 수 있습니다.

 

쉽게 생각하면 버튼을 누르고

이벤트가 발생하고

이벤트를 처리하고

프로그램은 이 과정의 무한 반복입니다.

 

QMainWindow 의 사용

지금까지 QWidget 클래스를 사용했습니다.

그런데 QWidget 은 일반적 프레임이고 base 일뿐

뭔가 편리하지는 않습니다.

 

QMainWindow 클래스는 윈도우에 특화된

객체입니다. 메뉴바와 스테이터스바가

기본으로 탑재되있고 좀더 윈도우스러운

레이아웃이 미리 준비되어 있습니다.

 

예제

간단히 예제를 보고 넘어가겠습니다.

QtWidgets 의 QMainWindow 로 바뀌었습니다.

 

setCentralWidget 은 중앙에 들어가는 위젯입니다.

어차피 레이아웃 클래스를 쓸거지만

일단 자체 레이아웃으로 보면 됩니다.

 

메뉴바의 경우 그냥 menuBar 인스턴스를

만들 수 있습니다.

 

메뉴바에는 액션을 추가할 수 있는데

액션이란 하위 선택메뉴를 말합니다.

 

from PyQt5 import QtWidgets
import sys

class PyQtWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(PyQtWindow, self).__init__()
        self.setup()


    def setup(self):
        self.setWindowTitle('My PyQt5 Window')
        self.setGeometry(700, 700, 320, 240)

        self.central_widget = QtWidgets.QWidget(self)
        self.quit_btn = QuitBtn(self.central_widget)
        self.setCentralWidget(self.central_widget)

        exit_action = QtWidgets.QAction('Exit', self)
        exit_action.triggered.connect(self.close)

        menu = self.menuBar()
        file_menu = menu.addMenu('File')
        file_menu.addAction(exit_action)

        self.show()

    def closeEvent(self, event):
        reply = QuitMsg().exec_()
        if reply == QtWidgets.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


class QuitMsg(QtWidgets.QMessageBox):
    def __init__(self):
        QtWidgets.QMessageBox.__init__(self)
        self.setText("Want to Quit?")
        self.addButton(self.No)
        self.addButton(self.Yes)

class QuitBtn(QtWidgets.QPushButton):
    def __init__(self, frame):
        QtWidgets.QPushButton.__init__(self,frame)
        self.setText("Quit")
        self.move(100,100)
        self.clicked.connect(QtWidgets.qApp.quit)
        # self.clicked.connect(frame.close)
        self.setToolTip("Close the window")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myWin = PyQtWindow()
    app.exec_()

다른 곳은 기존 코드와 같습니다.

메뉴의 액션에도 triggered.connect 가 있는데

여기에 메뉴를 클릭했을 때 수행할 메소드를 넣습니다.

Exit 니까 close 이죠. 클릭하면 closeEvent 를 수행합니다.

PyQt5 메뉴
PyQt5 메뉴

 

요약

일단 기본적인 부분을 커버하고 있는데

코드를 보다보면 좀 지겨워질 수 있습니다.

이런 것을 매번 하드코딩으로 만들어야 한다면

매우 지겨울 수 밖에 없습니다.

 

허나 PyQt5에는 designer 가 있습니다.

처음에는 구조를 이해하기 위해서

하나씩 손으로 코딩하지만

나중에는 designer 를 사용할 것이니 걱정할 필요가 없습니다.

 

GUI 프로그램은 빨리 만드는 것에 묘미가 있습니다.

 

요새는 UI UX 라고 중요시 여기는데

그건 웹서비스를 개발할 때 더 중요할 겁니다.

 

또 고전적 데스크탑 앱을 위한 GUI는

좀 디자인 적인 부분에 한계가 있습니다.

 

요새는 자바스크립트로 뭐든지 웹에 만들어 놓을 수 있으니까요.

 

PyQt5 를 사용한다면 좀 전문적인

목적의 앱에 적합하다고 보이는데요.

 

웹에 비하면 레이아웃적인 한계가

있는 것도 사실이니 너무 고민할 필요는 없습니다.

 

그럼 다음 포스팅에는 레이아웃에 대해서 알아보겠습니다.

공유하기

facebook twitter kakaoTalk kakaostory naver band