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