Шаг 50.
Библиотека PyQt5.
Обработка сигналов и событий. Генерация сигналов

    На этом шаге мы рассмотрим различные способы генерации сигналов.

    В некоторых случаях необходимо сгенерировать сигнал программно. Например, при заполнении последнего текстового поля и нажатии клавиши Enter можно имитировать нажатие кнопки ОК и тем самым выполнить подтверждение ввода пользователя. Осуществить генерацию сигнала из программы позволяет метод emit() класса QObject. Форматы этого метода:

  <Компонент>.<Сигнал>.emit ([<Данные>]) 
  <Компонент>.<Сигнал>[<Тип>].emit([<Данные>])

    Метод emit() всегда вызывается у объекта, которому посылается сигнал. Пример:

  button.clicked.emit()

    Сигналу и, соответственно, его обработчику можно передать данные, указав их в вызове метода emit(). Примеры:

  button.clicked[bool].emit(False) 
  button.clicked["bool"].emit(False)

    Также мы можем создавать свои собственные сигналы. Для этого следует определить в классе атрибут, чье имя совпадет с наименованием сигнала. Отметим, что это должен быть атрибут класса, а не экземпляра. Далее мы присвоим вновь созданному атрибуту результат, возвращенный функцией pyqtSignal() из модуля QtCore. Формат функции:

  <Объект сигнала> = pyqtSignal(*<Типы данных>[, name=<Имя сигнала>])

    В параметре <Типы данных> через запятую задаются названия типов данных, передаваемых сигналу, - например: bool или int:

  mysignal1 = QtCore.pyqtSignal(int) 
  mysignal2 = QtCore.pyqtSignal(int, str)

    При использовании типа данных C++ его название необходимо указать в виде строки:

  mysignal3 = QtCore.pyqtSignal("QDate")

    Если сигнал не принимает параметров, параметр <Типы данных> не указывается.

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

  mysignal4 = QtCore.pyqtSignal([int], [str])

    По умолчанию название создаваемого сигнала будет совпадать с названием атрибута класса. Однако мы можем указать для сигнала другое название, после чего он будет доступен под двумя названиями: совпадающим с именем атрибута класса и заданным нами. Для указания названия сигнала применяется параметр name:

  mysignal = QtCore.pyqtSignal(int, name = 'mySignal')

    В качестве примера создадим окно с двумя кнопками. Для этих кнопок назначим обработчики сигнала clicked (нажатие кнопки). Внутри обработчика щелчка на первой кнопке сгенерируем два сигнала: первый будет имитировать нажатие второй кнопки, а второй станет пользовательским, привязанным к окну. Внутри обработчиков выведем сообщения в окно консоли.

# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtWidgets
class MyWindow(QtWidgets.QWidget):
    mysignal = QtCore.pyqtSignal(int, int)
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.setWindowTitle("Генерация сигнала из программы")
        self.resize(300, 100)
        self.button1 = QtWidgets.QPushButton("Нажми меня")
        self.button2 = QtWidgets.QPushButton("Кнопка 2")
        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.button1)
        vbox.addWidget(self.button2)
        self.setLayout(vbox)
        self.button1.clicked.connect(self.on_clicked_button1)
        self.button2.clicked.connect(self.on_clicked_button2)
        self.mysignal.connect(self.on_mysignal)
    def on_clicked_button1(self):
        print("Нажата кнопка button1")
        # Генерируем сигналы
        self.button2.clicked[bool].emit(False)
        self.mysignal.emit(10, 20)
    def on_clicked_button2(self):
        print("Нажата кнопка button2")
    def on_mysignal(self, x, y):
        print("Обработан пользовательский сигнал mysignal()")
        print("x =", x, "y =", y)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())
Архив с файлом можно взять здесь.

    Результат выполнения приложения приведен на рисунке 1:


Рис.1. Результат работы приложения

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

  mysignal = QtCore.pyqtSignal(QtCore.QVariant)
  .   .   .   .
  self.mysignal.emit(20)
  self.mysignal.emit("Привет!")
  self.mysignal.emit([1, "2"])

    Сгенерировать сигнал можно не только с помощью метода emit(). Некоторые компоненты предоставляют методы, которые посылают сигнал. Например, у кнопок существует метод click(). Используя этот метод, инструкцию:

  button.clicked.emit()
можно записать следующим образом:
  button.click()

    Более подробно такие методы мы будем рассматривать при изучении конкретных компонентов.

    На следующем шаге мы рассмотрим передачу данных в обработчик.




Предыдущий шаг Содержание Следующий шаг