개발/Python

emit () 및 pyqtSignal ()의 PyQt 적절한 사용

MinorMan 2020. 9. 22. 04:36
반응형

<질문>

간단한 신호 슬롯 메커니즘을 생각해 내기 위해 PyQt5에 대한 문서를 읽고 있습니다. 디자인을 고려하여 중단되었습니다.

다음 코드를 고려하십시오.

import sys
from PyQt5.QtCore import (Qt, pyqtSignal)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
    QVBoxLayout, QApplication)


class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def printLabel(self, str):
        print(str)

    def logLabel(self, str):
        '''log to a file'''
        pass

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)

        #redundant connections
        sld.valueChanged.connect(lcd.display)
        sld.valueChanged.connect(self.printLabel)
        sld.valueChanged.connect(self.logLabel)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

슬라이더의 변경 사항을 추적하기 위해 변경 사항을 인쇄하고 기록하기 만하면됩니다. 코드가 마음에 들지 않는 점은 동일한 정보를 3 개의 다른 슬롯에 전송하기 위해 sld.valueChanged 슬롯을 세 번 호출해야한다는 것입니다.

단일 슬롯 함수에 정수를 보내는 내 자신의 pyqtSignal을 만들 수 있습니까? 그리고 슬롯 기능이 필요한 변경 사항을 내 보냅니 까?

  • PyQt Signal-Slot 문서에 목적에 대한 좋은 예가 없기 때문에 emit ()의 목적을 완전히 이해하지 못할 수도 있습니다. 우리에게 주어진 것은 매개 변수없이 emit를 구현하는 방법의 예입니다.

내가하고 싶은 것은 방출 함수를 처리하는 함수를 만드는 것입니다. 다음을 고려하세요:

import sys
from PyQt5.QtCore import (Qt, pyqtSignal)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
    QVBoxLayout, QApplication)


class Example(QWidget):

    def __init__(self):
        super().__init__()

        #create signal
        self.val_Changed = pyqtSignal(int, name='valChanged')

        self.initUI()

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)

        sld.val_Changed.connect(self.handle_LCD)
        self.val_Changed.emit()

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()

    def handle_LCD(self, text):
        '''log'''
        print(text)
        '''connect val_Changed to lcd.display'''

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

여기에는 분명히 몇 가지 심각한 디자인 결함이 있습니다. 함수 호출 순서에 머리를 감쌀 수는 없습니다. 그리고 pyqtSignal을 올바르게 구현하지 않습니다. 그러나 다음 세 가지 사항을 올바르게 설명하면 적절한 앱을 만드는 데 도움이 될 것이라고 생각합니다.

내가하려는 작업에 대한 코드를 완전히 변경해도됩니다. 좋은 스타일 영역에 있는지 아직 파악하지 못했기 때문입니다.


<답변1>

자신 만의 슬롯 (모든 파이썬 호출 가능)을 정의하고이를 신호에 연결 한 다음 해당 슬롯에서 다른 슬롯을 호출 할 수 있습니다.

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def printLabel(self, str):
        print(str)

    def logLabel(self, str):
        '''log to a file'''
        pass

    @QtCore.pyqtSlot(int)
    def on_sld_valueChanged(self, value):
        self.lcd.display(value)
        self.printLabel(value)
        self.logLabel(value)

    def initUI(self):

        self.lcd = QLCDNumber(self)
        self.sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(self.lcd)
        vbox.addWidget(self.sld)

        self.setLayout(vbox)
        self.sld.valueChanged.connect(self.on_sld_valueChanged)


        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')

또한 자신의 시그널을 정의하려면 클래스 변수로 정의해야합니다.

class Example(QWidget):
    my_signal = pyqtSignal(int)

pyqtSignal에 대한 인수는 해당 신호에서 방출 될 객체 유형을 정의하므로이 경우 다음을 수행 할 수 있습니다.

self.my_signal.emit(1)

특정 신호 값을 슬롯 함수로 보내기 위해 emit를 다시 구현할 수 있습니다. 이전에 기존의 신호 방법과 다른 값을 보내야하는 이유도 아직 명확하지 않습니다.

일반적으로 내장 된 신호를 방출해서는 안됩니다. 정의한 신호 만 방출하면됩니다. 신호를 정의 할 때 유형이 다른 여러 서명을 정의 할 수 있으며 슬롯은 연결할 서명을 선택할 수 있습니다. 예를 들어 다음과 같이 할 수 있습니다.

my_signal = pyqtSignal([int], [str])

이것은 두 개의 다른 시그니처를 가진 신호를 정의 할 것이고 슬롯은 어느 하나에 연결할 수 있습니다

@pyqtSlot(int)
def on_my_signal_int(self, value):
    assert isinstance(value, int)

@pyqtSlot(str)
def on_my_signal_str(self, value):
    assert isinstance(value, str)

실제로는 신호 서명에 과부하가 거의 걸리지 않습니다. 일반적으로 동일한 신호를 오버로드하는 대신 다른 서명을 사용하여 두 개의 개별 신호를 생성합니다. 그러나 Qt에는 이런 방식으로 오버로드되는 신호가 있기 때문에 PyQt에서 존재하고 지원됩니다 (예 : QComboBox.currentIndexChanged).

반응형