События и сигналы PyQt6
В этой части руководства мы исследуем события и сигналы в программах PyQt6.
События в PyQt6
Приложения с графическим интерфейсом управляются событиями. События в первую очередь инициируются пользователем приложения, но также могут генерироваться другими способами, такими как подключение к Интернету, оконные менеджеры или таймеры. Когда мы вызываем метод приложения exec()
, приложение входит в основной цикл. Основной цикл получает события и отправляет их объектам.
В модели событий есть три элемента:
- источник событий источник событий
- объект события объект события
- Цель события Цель события
Источник событий — это объект изменения состояния, генерирующий события. Объект события (событие) инкапсулирует изменение состояния источника события. Цель события — это объект, который необходимо уведомить. Объект источника события делегирует задачу обработки события цели события.
PyQt6 имеет уникальный механизм сигналов и слотов для обработки событий, используемый для связи между объектами и запускаемый при возникновении определенного события. Слот может представлять собой любой вызываемый скрипт Python. Когда сигнализируется о соединении, вызывается скрипт слота.
Аннотация: Это можно понимать как хуки или обратные вызовы.
Сигналы и слоты PyQt6
В следующем примере показаны сигналы и слоты PyQt6.
# file: signals_slots.py
#!/usr/bin/python
"""
ZetCode PyQt6 tutorial
本例中,把 QSlider 触发的事件和 QLCDNumber 插槽绑定起来
Author: Jan Bodnar
Website: zetcode.com
"""
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (QWidget, QLCDNumber, QSlider,
QVBoxLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
lcd = QLCDNumber(self)
sld = QSlider(Qt.Orientation.Horizontal, self)
vbox = QVBoxLayout()
vbox.addWidget(lcd)
vbox.addWidget(sld)
self.setLayout(vbox)
sld.valueChanged.connect(lcd.display)
self.setGeometry(300, 300, 350, 250)
self.setWindowTitle('Signal and slot')
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
В этом примере QtGui.QLCDNumber
и QtGui.QSlider
. Мы можем изменить число на дисплее, перетаскивая ползунок.
sld.valueChanged.connect(lcd.display)
valueChanged
Привяжите событие ползунка display
к слоту дисплея.
Отправитель — это объект, который запускает сигнал, получатель — это объект, который получает сигнал, а слот — это метод, который реагирует на сигнал.
PyQt6 переопределяет обработчики событий
В PyQt6 обработчики событий обычно переопределяются.
Аннотация: Все обработчики событий имеют реализацию по умолчанию, которая является событием по умолчанию. Событие по умолчанию может иметь свою собственную логику, например перетаскивание, щелчок, а некоторые могут быть просто пустой функцией. Пустые функции должны заново покрывать исходную реализацию для достижения цели обработки событий. Те, у которых есть функции обработки событий по умолчанию, также могут быть переопределены, например, отключение встроенного выбора перетаскивания или перезапись эффекта выбора перетаскивания и т. д.
# file: reimplement_handler.py
#!/usr/bin/python
"""
ZetCode PyQt6 tutorial
本例中,我们重新实现了一个事件处理器。
Author: Jan Bodnar
Website: zetcode.com
"""
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 350, 250)
self.setWindowTitle('Event handler')
self.show()
def keyPressEvent(self, e):
if e.key() == Qt.Key.Key_Escape.value:
self.close()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
В этом примере мы переопределяем keyPressEvent
обработчик событий для
def keyPressEvent(self, e):
if e.key() == Qt.Key.Key_Escape.value:
self.close()
Нажмите кнопку Escape, и приложение закроется.
Объект события PyQt6
Объект события — это объект Python, который содержит ряд атрибутов, описывающих событие, а конкретное содержимое зависит от инициированного события.
# file: event_object.py
#!/usr/bin/python
"""
ZetCode PyQt6 tutorial
本例中,在标签组件里,展示了鼠标的坐标。
Author: Jan Bodnar
Website: zetcode.com
"""
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QApplication, QGridLayout, QLabel
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
x = 0
y = 0
self.text = f'x: {
x}, y: {
y}'
self.label = QLabel(self.text, self)
grid.addWidget(self.label, 0, 0, Qt.AlignmentFlag.AlignTop)
self.setMouseTracking(True)
self.setLayout(grid)
self.setGeometry(300, 300, 450, 300)
self.setWindowTitle('Event object')
self.show()
def mouseMoveEvent(self, e):
x = int(e.position().x())
y = int(e.position().y())
text = f'x: {
x}, y: {
y}'
self.label.setText(text)
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
В этом примере координаты мыши отображаются в компоненте метки.
self.setMouseTracking(True)
По умолчанию отслеживание мыши отключено.При движении мыши компонент может получать события только при нажатии мыши. Включите отслеживание мыши, и вы сможете получать события, только перемещая мышь, не нажимая кнопку мыши.
def mouseMoveEvent(self, e):
x = int(e.position().x())
y = int(e.position().y())
...
e
Объект события, содержащий данные при срабатывании события. С помощью методов position().x()
и e.position().y()
можно получить координаты мыши.
self.text = f'x: {
x}, y: {
y}'
self.label = QLabel(self.text, self)
Значения координат x и y отображаются в QLabel
компоненте.
Триггер событий PyQt6
Иногда вам нужно знать, кто является триггером события, и в PyQt6 есть метод, позволяющий получить триггер события.
event_sender.py
#!/usr/bin/python
"""
ZetCode PyQt6 tutorial
In this example, we determine the event sender
object.
Author: Jan Bodnar
Website: zetcode.com
"""
import sys
from PyQt6.QtWidgets import QMainWindow, QPushButton, QApplication
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn1 = QPushButton("Button 1", self)
btn1.move(30, 50)
btn2 = QPushButton("Button 2", self)
btn2.move(150, 50)
btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.buttonClicked)
self.statusBar()
self.setGeometry(300, 300, 450, 350)
self.setWindowTitle('Event sender')
self.show()
def buttonClicked(self):
sender = self.sender()
msg = f'{
sender.text()} was pressed'
self.statusBar().showMessage(msg)
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
В этом примере есть две кнопки. buttonClicked
Вызов метода триггера определяет, какая кнопка вызвала событие.
btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.buttonClicked)
Обе кнопки привязаны к одному слоту.
def buttonClicked(self):
sender = self.sender()
msg = f'{
sender.text()} was pressed'
self.statusBar().showMessage(msg)
В строке состояния приложения показано, какая кнопка была нажата.
Графика: триггер события
Триггерный сигнал PyQt6
QObject
Сигналы могут запускаться активно. В примере ниже показано, как вызвать пользовательский сигнал.
# file: custom_signal.py
#!/usr/bin/python
"""
ZetCode PyQt6 tutorial
In this example, we show how to
emit a custom signal.
Author: Jan Bodnar
Website: zetcode.com
"""
import sys
from PyQt6.QtCore import pyqtSignal, QObject
from PyQt6.QtWidgets import QMainWindow, QApplication
class Communicate(QObject):
closeApp = pyqtSignal()
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.c = Communicate()
self.c.closeApp.connect(self.close)
self.setGeometry(300, 300, 450, 350)
self.setWindowTitle('Emit signal')
self.show()
def mousePressEvent(self, e):
self.c.closeApp.emit()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Создан closeApp
сигнал, который срабатывает при нажатии мыши и QMainWindow
привязан к закрытому слоту.
class Communicate(QObject):
closeApp = pyqtSignal()
Свойства внешнего класса Communicate pyqtSignal
Создает сигнал.
self.c = Communicate()
self.c.closeApp.connect(self.close)
Пользовательский сигнал closeApp
привязан QMainWindow
к слоту выключения файла .
def mousePressEvent(self, event):
self.c.closeApp.emit()
При нажатии кнопки мыши в окне closeApp
срабатывает сигнал и программа завершает работу.
В этой главе руководства мы рассмотрели сигналы и слоты.