본문 바로가기
대동단결 Python

사용자 정의 시그널 만들기

by 즐거운 지니 2021. 9. 11.
반응형

시그널이란 객체는 시그널을 발생 시키는 위치에서 슬롯함수를 호출하도록 설계되어 있다. 즉, 해당 위치에서 함수를 호출한 것과 동일하게 동작된다.

먼저 시그널을 사용하기 위해 패키지가 필요하다.

from PyQt5.QtCore import *

시그널을 만든다. 중요한 것은 시그널은 클래스변수이어야 하고, 시그널을 포함하는 클래스는 QObject 또는 그 후손이어야 한다.

class 클래스명(QObject):
    시그널명 = pyqtSignal(변수타입)

이 시그널이 동작되기 위해서는 반드시 클래스가 객체화 되어야 한다. 시그널은 (살아있는) 객체에서만 의미가 있기 때문이다.

변수타입으로는 다음과 같은 것들이 있다.

  • bool(boolean) : 참, 거짓 두가지 값을 표현
  • int(integer) : 정수
  • float(floating-point number) : 실수
  • complex(complex number) : 복소수
  • str(string) : 문자열
  • list : 순서가 있는 값들의 집합
  • tuple : 리스트와 같이 순서가 있는 값들의 집합이지만 읽기전용
  • set : 순서가 없고 중복되지 않는 값들의 집합
  • dict(dictionary) : 키와 값의 쌍으로 데이터 집합

변수타입은 시그널이 발생하는 위치에서 슬롯함수에 전달하고픈 데이터의 타입이다.

시그널의 발생은 다음과 같이 구현한다.

self.시그널명.emit(파라미터들..)

시그널을 슬롯함수와 연결하기 위해서는 다음과 같이 구현한다.

self.시그널명.connect(슬롯함수)

테스트 코드는 다음과 같다.

from PyQt5.QtCore import *

class TheClass(QObject):
    theSignal = pyqtSignal(str)

    def __init__(self):
        super(TheClass, self).__init__()
        #self.theSignal = pyqtSignal(str)
        self.theSignal.connect(self.theSlot)

    def run(self):
        print('여기서 시그널을 발생할 것이다.')
        self.theSignal.emit('선풍기')
        print('---')

    def theSlot(self, what):
        print(f'나는 {what}를(을) 갖고싶다.')

def anotherFucn(what):
    print(f'너는 {what} 갖고 싶니?')


if __name__ == '__main__':
    myclass = TheClass()
    myclass.run()
    print('객체 외부에서 슬롯 연결 및 시그널 발생')
    myclass.theSignal.connect(anotherFucn)
    myclass.theSignal.emit('냉장고')
    print('프로그램 종료')

 

C:\ProgramData\Anaconda3\python.exe D:/works/pythonProject/genieDonkiwoom/signalTest.py
여기서 시그널을 발생할 것이다.
나는 선풍기를(을) 갖고싶다.
---
객체 외부에서 슬롯 연결 및 시그널 발생
나는 냉장고를(을) 갖고싶다.
너는 냉장고 갖고 싶니?
프로그램 종료

Process finished with exit code 0

이벤트루프와 함께 사용할 때, 쓰레드에서 emit()을 호출하면 쓰레드와 슬롯함수가 병렬로 진행한다. 하지만 메인쓰레드에서는  pyqtSignal의 emit()함수가 실행되는 즉시 슬롯함수로 넘어간다. 슬롯함수를 다 종료하고 나서야 다음 문장으로 넘어간다.

import sys
import threading
import time

from PyQt5.QtCore import QEventLoop, QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication


class CustomEvent(QObject):
    custom_signal = pyqtSignal(list)
    second_signal = pyqtSignal()

def custom_event_handler(event):
    print("Custom event occurred")
    event[0].second_signal.emit()
    print('두번째시그널 발사')


def second_signal_handler():
    print("두번째 시그널에 대한 응답")
    time.sleep(1)
    print('두번째함수 종료')

app = QApplication(sys.argv)
loop = QEventLoop(app)

custom_event = CustomEvent()
custom_event.custom_signal.connect(custom_event_handler)
custom_event.second_signal.connect(second_signal_handler)

loop.processEvents(QEventLoop.AllEvents)

def run(event):
    while True:
        event.custom_signal.emit([event])
        print('시그널 발사',end='')
        time.sleep(1)
        print('뒤 1초 경과')

threading.Thread(target=run, args=(custom_event,), daemon=True).start()

loop.exec_()
C:\ProgramData\Anaconda3\python.exe D:\works\pythonProject\genieDonkiwoom_pysimplegui\signalTest.py 
시그널 발사Custom event occurred
두번째 시그널에 대한 응답
두번째함수 종료
두번째시그널 발사
뒤 1초 경과
시그널 발사Custom event occurred
두번째 시그널에 대한 응답

Process finished with exit code -1073740791 (0xC0000409)
반응형

댓글