본문 바로가기
대동단결 Python

사용자 정의 시그널-슬롯

by 즐거운 지니 2021. 5. 14.
반응형

pyQt5기반의 파이썬 GUI 프로그래밍에는 시그널과 슬롯 이라는 개념이 있다. 예컨데 버튼을 클릭하는 순간 버튼이 클릭되었다는 시그널(이벤트 시그널)이 발생되고, 그 때 실행할 함수를 슬롯(콜백함수) 이라 한다. pyQt5에서 제공하는 모든 GUI 객체들은 제 나름대로의 필요한 시그널 들이 정의 되어 있다. 여기서는 사용자 정의 시그널을 만들고 사용해 본다.

참조문서

Support for Signals and Slots - PyQt 5.7 Reference Guide

Qt의 주요 기능 중 하나는 시그널과 슬롯을 사용하여 객체간에 통신하는 것.

시그널이 발생하면 그 때 실행해야할 함수가 실행된다. 그 함수를 슬롯이라 한다. 이것이 가능하도록 시그널과 슬롯을 연결하여야 한다.

signal/slot 메커니즘은 다음과 같은 특징들이 있다.

  • A signal may be connected to many slots.
  • A signal may also be connected to another signal.
  • Signal arguments may be any Python type.
  • A slot may be connected to many signals.
  • Connections may be direct (ie. synchronous) or queued (ie. asynchronous).
  • Connections may be made across threads.
  • Signals may be disconnected.

시그널은 signal = pyqtSignal() 의 형태로 정의 된다. 중요한 것은 signal 이 클래스변수로 정의되어야 한다는 것이다. 그렇지 않으면 슬롯과 연결 할 수 없다.

class MyObject(QObject):
    # 시그널은 반드시 클래스 변수이어야 해유
    signaled = pyqtSignal(object)

위 코드에서 처럼 signaled 는 MyObject 클래스의 클래스변수로 정의되었다. 여기서 object는 시그널 발생시 슬롯에 전달할 파라미터 데이터 타입이다. 사용가능한 타입들은 파이썬에서 통용되는 대부분의 오브젝트들이다. 예를들어, int, float, complex, str, object, list, set, tuple, dict ...

두번째로 중요한 것은 클래스가 반드시 객체로 인스탄스화 되어야 시그널도 사용할 수 있다는 것이다. 언바운드 시그널은 해당 클래스가 객체화 되어야 발생할 수 있는 시그널 (바운드 시그널)로 활성화 된다.

obj = MyObject()    # 시그널은 살아있는 객체 속에서만 의미 있는 거쥬

위 코드 이후 비로소 obj.signaled는 방출(시그널 발생)될 수도 있고, 슬롯연결 될 수도 있다.

먼저 시그널 발생시 연결할 함수를 만들어 둔다.

def signaledSlot(e):
    print(f'signal emitted with the event {e}.')

이 때 정의된 시그널의 파라미터(object)와 슬롯의 파라미터(e)가 타입일치하도록 한다.

이제 시그널과 슬롯을 연결하자.

obj.signaled.connect(signaledSlot)  # 객체 속의 시그널은 connect 될 수 있어유

마지막으로 시그널을 발생 시킨다.

obj.signaled.emit('EVENT')          # 객체 속의 시그널은 emit 될 수 있어유

여기서 'EVENT' 는 시그널의 파라미터와 슬롯의 파라미터에 대응하는 값이다. 즉 3 값이 모두 같은 타입이어야 한다.

시그널이 발생되었으니 해당 슬롯함수가 실행된다.

signal emitted with the event EVENT.

전체 코드는 다음과 같다.

# https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html
from PyQt5.QtCore import *


class MyObject(QObject):
    # 시그널은 반드시 클래스 변수이어야 해유
    signaled = pyqtSignal(object)

def signaledSlot(e):
    print(f'signal emitted with the event {e}.')


obj = MyObject()    # 시그널은 살아있는 객체 속에서만 의미 있는 거쥬
obj.signaled.connect(signaledSlot)  # 객체 속의 시그널은 connect 될 수 있어유
obj.signaled.emit('EVENT')          # 객체 속의 시그널은 emit 될 수 있어유

반응형

댓글