PyQt правильное использование emit() и pyqtSignal()

Я читаю некоторую документацию по 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_())

чтобы отслеживать изменения, внесенные в слайдер, я просто печатаю и регистрирую внесенные изменения. Что мне не нравится в коде, так это то, что я должен вызвать sld.valueChanged слот трижды, чтобы отправить ту же информацию в 3 разных слота.

можно ли создать свой собственный pyqtSignal который отправляет целое число в одну функцию слота. И в свою очередь функция слота испускает изменения, которые необходимо сделать?

  • может быть, я не совсем понимаю цель emit() потому что нет хороших примеров его цели в PyQt сигнал-слот документы. Всем нам дан пример, как реализовать 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 правильно. Однако я считаю, что правильное указание следующих 3 пунктов поможет мне создать правильное приложение:

  1. для заданного сигнала: сигнал на функцию слота. Слот можно reimplemented для использования сигнала ценности.
  2. производства pyqtSignal объект с некоторыми параметрами. Пока не ясно, какова цель этих параметров и чем они отличаются от параметров "испускания".
  3. emit смогите быть reimplemented для посылки специфических значений сигнала к функции шлица. Также пока не ясно, почему мне нужно будет отправлять разные значения из ранее существующих методов сигнала.

не стесняйтесь полностью изменять код для того, что я пытаюсь сделать, потому что у меня нет все же выяснил, если его в области хорошего стиля.

1 ответов


вы можете определить свой собственный слот (любой вызываемый python) и подключить его к сигналу, а затем вызвать другие слоты из этого одного слота.

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 определить типы объектов, которые будут emit ' d по этому сигналу, так что в этом случае, вы могли бы сделать

self.my_signal.emit(1)

испускать можно reimplemented для посылки специфического сигнала значения для слота функция. Также пока не ясно, почему мне нужно будет отправлять разные значения из ранее существующих методов сигнала.

вы вообще не должны испускать встроенные сигналы. Вам нужно только излучать сигналы, которые вы определяете. При определении сигнала можно определить различные сигнатуры с разными типами, а слоты могут выбрать сигнатуру, к которой они хотят подключиться. Например, вы можете сделать это

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)

на практике я редко перегружаю сигнатуры сигналов. Обычно я просто создаю два отдельных сигнала с разными сигнатурами, а не перегружаю один и тот же сигнал. Но он существует и поддерживается в PyQt, потому что Qt имеет сигналы, которые перегружены таким образом (например. QComboBox.currentIndexChanged)