본문 바로가기

코딩/Python

[Python/파이썬] PyQt5 - 사용자 정의 시그널(Custom Signal)과 Emit 사용법

반응형

1편 : 2021.03.06 - [코딩/Python] - [Python/파이썬] PyQT5 및 QT Designer 소개, .ui 파일 .py로 변환 방법

2편 : 2021.03.28 - [코딩/Python] - [Python/파이썬] PyQt5를 통한 GUI 구성 및 사용법 이해하기

3편 : 2021.03.29 - [코딩/Python] - [Python/파이썬] PyQt5 사용시 필요한 쓰레드 개념 이해 - 1

4편 : 2021.03.30 - [코딩/Python] - [Python/파이썬] PyQt5 사용시 필요한 쓰레드 개념 이해-2 (GUI 응답없음 해결)

5편 : 2021.07.19 - [코딩/Python] - [Python/파이썬] PyQt5 - 시그널(Signal)과 슬롯(Slot) 개념

6편 : 2021.07.22 - [코딩/Python] - [Python/파이썬] PyQt5 - 사용자 정의 시그널(Custom Signal)과 Emit 사용법


  이전 포스팅에서는 PyQt5에서 시그널(Signal)과 슬롯(Slog)의 개념에 대해서 알아봤다. PyQt5에서는 Signal을 발생시키는 기본적인 Object들이 있지만(버튼누르기, 콤보박스 선택 등), 사용자가 직접 Signal을 정의하는 방법도 있다. 이 것을 사용자 정의 시그널(Custom Signal)이라고 한다.

 

  사용자 정의 시그널을 사용하면 emit이라는 메서드를 통해 다른 클래스에서 GUI에 특정 값을 전달할 수 있다. 사용자 정의 시그널 이해를 위해 아래 가상의 예시 코드를 작성해보았다. 코드는 위키독스-'파이썬을 이용한 비트코인 자동매매 (개정판)을 참고하였다.

 

 

<전체 코드>

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal

#사용자 정의 시그널 사용을 위한 클래스 정의
class CustomSignal(QObject):
    signal = pyqtSignal(int, str) #반드시 클래스 변수로 선언할 것

    def run(self):
        tempstr = "emit으로 전달"
        for i in range(1, 11):
            self.signal.emit(i, tempstr) #customFunc 메서드 실행시 signal의 emit 메서드사용
    
class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        customsignal = CustomSignal() #Mysignal 클래스의 객체 선언
        customsignal.signal.connect(self.funcEmit) #객체에 대한시그널 및 슬롯 설정
        customsignal.run() #객체의 customFunc 메서드 실행

    #customFunc에서 emit 메서드 실행시 GUI에서 받음.
    @pyqtSlot(int, str)
    def funcEmit(self, i, tempstr):
        self.i = i #emit을 통해 받은 값을 GUI 객체 변수에 저장
        self.tempstr = tempstr 
        print(str(self.i)+"번째 출력 : ", self.tempstr) #출력해보기


if __name__ == "__main__":    
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    app.exec_()

 

 

<결과>

<코드 실행시 결과>

 

 

  결과 이미지에서 확인해보면 터미널 창에 사용자 정의 signal 클래스에서 GUI에서 읽어와 터미널 창에 출력하는 것을 확인할 수 있다. 

 

 

 

1. 모듈 import

 

 

<코드>

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal

 

-. 위 코드의 사용자 정의 시그널 및 emit 메서드르 사용하려면 PyQt5.Qtcore 모듈의 pyqtSlot 메서드, QObject 클래스 ,pyqtSignal 클래스가 import되어 있어야 한다.

 

 

 

2. 사용자 정의 Signal : Class CustomSignal(QObject)

 

 

  CustomSignal이라는 사용자 정의 시그널 클래스를 정의한 부분이다. 

 

 

<코드>

#사용자 정의 시그널 사용을 위한 클래스 정의
class CustomSignal(QObject):
    signal = pyqtSignal(int, str) #반드시 클래스 변수로 선언할 것

    def run(self):
        tempstr = "emit으로 전달"
        for i in range(1, 11):
            self.signal.emit(i, tempstr) #customFunc 메서드 실행시 signal의 emit 메서드사용

 

 

-. CustomSignal 클래스는 PyQt5.Qtcore 모듈의 QObject 클래스를 상속받는다. QObject를 상속받아야 Signal과 GUI를연결할 수 있다.

 

-. pyqtSinal 클래스의 인스턴스인 signal은 반드시 클래스 변수(인스턴스 변수)로 선언되어야 한다. 클래스 변수에 대해서는 아래 정리한 포스팅이 있으니 참고!

(참고링크 : 2021.03.22 - [코딩/Python] - [Python/파이썬] Class(클래스) 기초 정리 - 4 : 추상 클래스, 클래스 변수)

 

-. pyqtSignal 클래스 선언시 emit으로 GUI로 전달 될 값들의 매개변수 변수형을 기록한다. 위 코드에 따르면 int와 str이전달된다.

 

-. self.signal.emit(i, tempstr) : run 메서드 실행시 GUI로 변수 i와 tempstr이 전달된다. 두 변수의 타입은 int str이다.

 

 

 

2. 사용자 정의 Signal에 대한 Slot

 

 

  GUI쪽 Class에선 사용자 정의 SIgnal에 대한 Slot을 구현한다. Slot에서는 emit으로 전달받은 값을 사용해 GUI에 활용할 수 있다. 주석을 달아놓긴 했지만 중요한 부분은 아래 추가 설명하였다.

 

 

<코드>

#GUI
class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        customsignal = CustomSignal() #Mysignal 클래스의 객체 선언
        customsignal.signal.connect(self.funcEmit) #객체에 대한시그널 및 슬롯 설정
        customsignal.run() #객체의 customFunc 메서드 실행

    #customFunc에서 emit 메서드 실행시 GUI에서 받음.
    @pyqtSlot(int, str)
    def funcEmit(self, i, tempstr):
        self.i = i #emit을 통해 받은 값을 GUI 객체 변수에 저장
        self.tempstr = tempstr 
        print(str(self.i)+"번째 출력 : ", self.tempstr) #출력해보기

 

-. customsignal.signal.connect(self.funcEmit)

: CustomSignal에 대한 인스턴스인 customsignal을 선언하고 Signal 및 Slot을 설정한 부분이다. 이전 편에서도 설명했지만 funcEmit은 signal 이 처리할 슬롯(=이벤트 핸들러)이다. 참고로, signal은 사용자 정의 시그널 Class(CustomSignal)에서 pyqtSignal(int,str)의 인스턴스이다.

 

-. customsignal.run( ) 

: customsignal 객체의 run 메서드를 사용한다. 1번에서 설명했지만 run 메서드에서는 GUI로 int, str 타입의 변수를 전달한다.

 

-. @pyqtSlot(int, str)

: @pyqtSlot은 PyQt5.Qtcore 모듈에 정의 된 데코레이터(Decortor)이다. 데코레이터 선언시 emit으로 방출되는 변수형 타입 2개 int, str를 꼭 적어줘야 정상적으로 동작한다. 데커레이터는 몇일전에 이 내용을 이해하기 위해 따로 정리한바가 있다. 아래 포스팅을 참고하면 좋을 것 같다.

 

-. def funcEmit(self, i, tempstr)

  GUI의 메서드인 funcEmit은 사용자 정의 시그널에서 emit 된 i (int type)과 tempstr(str type)을 받아 출력한다.

 


※ 데코레이터 관련 포스팅 링크

2021.07.14 - [코딩/Python] - [Python/파이썬] 데코레이터(Decorator) 1편 : 개념 및 기본 사용법

2021.07.16 - [코딩/Python] - [Python/파이썬] 데코레이터(Decorator) 2편 : 매개변수 있는 함수에 데코레이터 적용

 


 

4. 요약 (도식화)

 

 

  위에서 설명했던 내용이 굉장히 복잡한데 실행되는 순서대로 코드에 표시해보면 아래 이미지와 같다.

 

 

Signal 및 emit 실행 과정

 

 

  아직 해보진 않았지만 위 방법을 사용하면 GUI 창이 여러개인 프로그램에서 GUI끼리 값을 전달하고 상호작용하는게 가능할 것 같다. 이건 나중에 해보고 직접 포스팅을 해볼 예정.

 

 

728x90