在 PyQt4 编程教程的这一部分中,我们将探讨应用程序中发生的事件和信号。
活动内容
所有GUI应用程序都是事件驱动的。事件主要由应用程序的用户生成。但它们也可以通过其他方式产生:例如因特网连接、窗口管理器或定时器。当我们调用应用程序的exec_ method时,应用程序进入主循环。主循环获取事件并将其发送给对象。
在事件模型中,有三个参与者:
- 事件源
- 事件对象
- 事件目标
事件源是状态更改的对象。它产生事件。事件对象(event)封装事件源中的状态更改。事件目标是希望得到通知的对象。事件源对象将处理事件的任务委托给事件目标。
PyQt4有一个独特的信号和槽机制来处理事件。信号和插槽用于对象之间的通信。当特定事件发生时发出信号。插槽可以是任何Python可调用的。当连接到插槽的信号发出时,插槽被调用。
新的API
PyQt4.5引入了一个新风格的API来处理信号和插槽。
QtCore.QObject.connect(button, QtCore.SIGNAL(‘clicked()’), self.onClicked)
这是一个老式的API。
button.clicked.connect(self.onClicked)
新的风格更符合Python标准。
信号和插槽
这是一个简单的例子,演示了PyQt4中的信号和插槽。
#!/usr/bin/python
"""
ZetCode PyQt4 tutorial
In this example, we connect a signal
of a QtGui.QSlider to a slot
of a QtGui.QLCDNumber.
author: Jan Bodnar
website: zetcode.com
"""
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
lcd = QtGui.QLCDNumber(self)
sld = QtGui.QSlider(QtCore.Qt.Horizontal, self)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(lcd)
vbox.addWidget(sld)
self.setLayout(vbox)
sld.valueChanged.connect(lcd.display)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Signal & slot')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
在我们的示例中,我们显示了一个QtGui.QLCDNumber和一个QtGui.QSlider。我们通过拖动滑块旋钮来改变液晶显示器的数字。
sld.valueChanged.connect(lcd.display)
在这里,我们将滑块的valueChanged信号连接到LCD数字的显示槽。
发送器是一个发送信号的对象。接收器是接收信号的对象。时隙是对信号作出反应的方法。
重新实现事件处理程序
PyQt4中的事件通常通过重新实现事件处理程序来处理。
#!/usr/bin/python
"""
ZetCode PyQt4 tutorial
In this example, we reimplement an
event handler.
author: Jan Bodnar
website: zetcode.com
"""
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Event handler')
self.show()
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
在我们的示例中,我们重新实现了keyPressEvent事件处理程序。
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
如果我们单击Escape按钮,应用程序将终止。
事件发送者
有时,知道哪个小部件是信号的发送者是很方便的。为此,PyQt4有sender方法。
#!/usr/bin/python
"""
ZetCode PyQt4 tutorial
In this example, we determine the event sender
object.
author: Jan Bodnar
website: zetcode.com
"""
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
btn1 = QtGui.QPushButton("Button 1", self)
btn1.move(30, 50)
btn2 = QtGui.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('Event sender')
self.show()
def buttonClicked(self):
sender = self.sender()
self.statusBar().showMessage(sender.text() + ' was pressed')
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
在我们的示例中有两个按钮。在buttonClicked方法中,我们通过调用sender方法来确定我们点击了哪个按钮。
btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.buttonClicked)
两个按钮都连接到同一插槽。
def buttonClicked(self):
sender = self.sender()
self.statusBar().showMessage(sender.text() + ' was pressed')
我们通过调用sender方法来确定信号源。在应用程序的状态栏中,我们显示被按下按钮的标签。
发出信号
从QtCore.QObject创建的对象可以发出信号。在下面的例子中,我们将看到如何发送自定义信号。
#!/usr/bin/python
"""
ZetCode PyQt4 tutorial
In this example, we show how to emit a
signal.
author: Jan Bodnar
website: zetcode.com
"""
import sys
from PyQt4 import QtGui, QtCore
class Communicate(QtCore.QObject):
closeApp = QtCore.pyqtSignal()
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.c = Communicate()
self.c.closeApp.connect(self.close)
self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('Emit signal')
self.show()
def mousePressEvent(self, event):
self.c.closeApp.emit()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
我们创建了一个新的信号,叫做closeApp。此信号在鼠标按压事件期间发出。信号连接到QtGui.QMainWindow的闭合插槽。
class Communicate(QtCore.QObject):
closeApp = QtCore.pyqtSignal()
用QtCore.pyqtSignal作为外部Communicate类的类属性创建一个信号。
self.c.closeApp.connect(self.close)
自定义closeApp信号连接到QtGui.QMainWindow的关闭插槽。
def mousePressEvent(self, event):
self.c.closeApp.emit()
当我们用鼠标指针点击窗口时,就会发出close App信号。应用程序终止。
在PyQt4教程的这一部分中,我们介绍了信号和插槽。