[Python, PyQt] 사용자 정의 시그널, 객체간 통신하기
PyQt 에서는 객체간 통신을 위해 시그널(Signal)과 슬롯(Slot)이라는 것을 사용합니다
시그널은 이벤트, 슬롯은 이벤트 핸들러라고 생각하시면 됩니다
이번 포스팅에는 시그널과 슬롯을 이용하여 객체간 통신을 테스트 해보겠습니다.
테스트할 예제는 이렇습니다.
통신할 클래스
키보드 입력을 기다리는 KeyboardThread 클래스
메인 윈도우 MyWindow 클래스
시나리오
1. KeyboardThread에서 키보드 입력을 키다리다가 원하는 입력이 들어오면 MyWindow로 시그널을 보낸다.
2. MyWindow에서는 받은 시그널에 맞는 이벤트 처리 함수를 실행한다.
*테스트에 앞서 Thread 사용법, PyQt 사용에 대한 자세한 내용은 생략하겠습니다.
1. pyqtSignal, pyqtSlot 메서드 import
시그널과 슬롯을 사용하기위해 PyQt5.QtCore 모듈의 pyqtSignal, pyqtSlot 메서드를 import 시킵니다.
from PyQt5.QtCore import pyqtSignal, pyqtSlot
2. 시그널 만들기 - KeyboardThread 클래스
시그널을 보낼 KeyboardThread에서 signal이라는 이름의 시그널을 만듭니다.
emit으로 전달 될 값들의 매개변수 변수형을 넣어줄 수 있는데
이 시그널은 int 값을 전달합니다. (원하는 자료형으로 변경하거나 값을 보내지 않아도 된다.)
class KeyboardThread(QThread):
signal = pyqtSignal(int) #int값을 전달할 것 이다
def run(self):
while True:
if keyboard.is_pressed("ctrl+z"): # ctrl+z 입력이 들어오면
self.signal.emit(0) # 0 방출
elif keyboard.is_pressed("ctrl+x"): # ctrl+z 입력이 들어오면
self.signal.emit(1) # 1 방출
elif keyboard.is_pressed("ctrl+z"): # ctrl+z 입력이 들어오면
self.signal.emit(2) # 2 방출
time.sleep(0.1)
3. 슬롯 정의 - MyWindow 클래스
MyWindow에서는 KeyboardThread에서 시그널을 받아 이벤트를 처리할 것입니다
이벤트를 처리할 함수를 만들고 이벤트를 보내는 객체의 시그널에 연결시킵니다.
class MyWindow(QMainWindow, uic.loadUiType('./main.ui')[0]):
def __init__(self):
super().__init__()
self.setupUi(self)
self.keyboard_thread = KeyboardThread()
#keyboard_thread의 시그널을 get_keyboard_signal 함수에 연결한다.
self.keyboard_thread.signal.connect(self.get_keyboard_signal)
self.keyboard_thread.start()
#emit으로 방출되는 변수형은 int
@pyqtSlot(int)
def get_keyboard_signal(self, signal):
if signal == 0: #emit으로 0을 전달받으면
print("ctrl+z 시그널 들어옴")
elif signal == 1: #emit으로 1을 전달받으면
print("ctrl+x 시그널 들어옴")
elif signal == 2: #emit으로 2를 전달받으면
print("ctrl+c 시그널 들어옴")
실행결과
시그널과 슬롯을 다 정의하였고 프로그램을 실행시키면 어떻게 될까요?
KeyboardThread는 무한루프를 돌며 키보드 입력을 감지하고
ctrl + z 입력이 들어오면 MyWindow로 0을 방출, MyWindow에서 0을 받으면 "ctrl+z 시그널 들어옴" 을 출력
ctrl + x 입력이 들어오면 MyWindow로 1을 방출, MyWindow에서 0을 받으면 "ctrl+x 시그널 들어옴" 을 출력
ctrl + c 입력이 들어오면 MyWindow로 1을 방출, MyWindow에서 0을 받으면 "ctrl+c 시그널 들어옴" 을 출력할 것 입니다.