PyQt实践教学(三)--Events and signals in PyQt5

1220 查看

终于到了QT中最重要的部分了,就跟前端页面如果只有div+css的而少了JS会变得死气沉沉一样,事件驱动才是才是QT中的核心,它将静态的各个widget相互关联响应起来使得整个GUI变得生机盎然起来.
废话少说了,上实例~

Events

All GUI applications are event-driven. Events are generated mainly by the user of an application. But they can be generated by other means as well: e.g. an Internet connection, a window manager, or a timer. When we call the application's exec_() method, the application enters the main loop. The main loop fetches events and sends them to the objects.
In the event model, there are three participants:

  • event source
  • event object
  • event target

The event source is the object whose state changes. It generates events. The event object (event) encapsulates the state changes in the event source. The event target is the object that wants to be notified. Event source object delegates the task of handling an event to the event target.
PyQt5 has a unique signal and slot mechanism to deal with events. Signals and slots are used for communication between objects. A signal is emitted when a particular event occurs. A slot can be any Python callable. A slot is called when its connected signal is emitted.

Signals & slots(事件与信号)

# coding=utf-8
"""信号槽示例"""
import sys
from PyQt5.QtWidgets import QWidget,QLCDNumber,QSlider,QVBoxLayout,QApplication
from PyQt5.QtCore import Qt

class SignalSlot(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        lcd = QLCDNumber(self)
        slider = QSlider(Qt.Horizontal, self)

        v_box = QVBoxLayout()
        v_box.addWidget(lcd)
        v_box.addWidget(slider)

        self.setLayout(v_box)
        slider.valueChanged.connect(lcd.display)

        self.setGeometry(300,300,250,150)
        self.setWindowTitle("信号槽演示程序")
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    qb = SignalSlot()
    sys.exit(app.exec_())
  1. Here we connect a valueChanged signal of the slider to the display slot of the lcd number
  2. The sender is an object that sends a signal. The receiver is the object that receives the signal. The slot is the method that reacts to the signal.

Reimplementing event handler(重写事件的处理方法)

# coding=utf-8
"""用Esc键推出示例"""
import sys
from PyQt5.QtWidgets import QWidget,QApplication
from PyQt5.QtCore import Qt

class Escape(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.resize(250, 150)
        self.setWindowTitle("Esc退出演示程序")
        self.show()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    escape = Escape()
    sys.exit(app.exec_())
  1. In our example, we reimplement the keyPressEvent() event handler.
  2. If we click the Escape button, the application terminates.

Event sender (事件发送者)

#!/usr/bin/python3
# coding=utf-8
"""发射信号示例"""
import sys
from PyQt5.QtWidgets import QMainWindow,QPushButton,QApplication

class EmitSignal(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,290,150)
        self.setWindowTitle("发射信号演示程序")
        self.show()

    def buttonClicked(self):
        sender = self.sender()
        self.statusBar().showMessage(sender.text()+"was pressed")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    es = EmitSignal()
    sys.exit(app.exec_())
  1. We have two buttons in our example. In the buttonClicked() method we determine which button we have clicked by calling the sender() method.
  2. Both buttons are connected to the same slot.
  3. We determine the signal source by calling the sender() method. In the statusbar of the application, we show the label of the button being pressed.

emitting signals (发射信号)

# coding=utf-8
"""发射信号示例"""
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication,QWidget
from PyQt5.QtCore import pyqtSignal,QObject

class Communication(QObject):
    closeApp = pyqtSignal()

class EmitSignal(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.c = Communication()
        self.c.closeApp.connect(self.close)

        self.resize(250, 150)
        self.setWindowTitle("发射信号演示程序") 
        self.show()

    def mousePressEvent(self, QMouseEvent):
        self.c.closeApp.emit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    es = EmitSignal()
    sys.exit(app.exec_())
  1. We create a new signal called closeApp. This signal is emitted during a mouse press event. The signal is connected to the close() slot of the QMainWindow.
  2. A signal is created with the pyqtSignal() as a class attribute of the external Communicate class.
  3. The custom closeApp signal is connected to the close() slot of the QMainWindow.
  4. When we click on the window with a mouse pointer, the closeApp signal is emitted. The application terminates.

In this part of the PyQt5 tutorial, we have covered signals and slots.

总结:

  1. 当我们想要触发一个事件的时候,我们可以用某个信号的emit()方法发射此信号,此时会执行绑定在这个事件(即connect()的参数)上的方法.正如按钮的clicked属性一样,它也是一个信号,正如前面我在《PyQt实践教学(一)》中那个Closing a window那一节例子一样,clicked.connect()就是给这个信号绑定一个事件。这就是信号槽机制
  2. 一般都是Qwidgets中的某个组件中的某个表示变化的属性(非方法),例如clicked,valuChanged等,再接上connect(响应函数)来处理动态效果
  3. 被触发的组件叫做sender,而后触发组件再继续触发的动作或者函数叫slot