|
PyQt4 中的事件和信號(hào)
在本部分,我們將會(huì)探討事件和信號(hào)。
事件
在任何的 GUI 程序中,事件是很重要的部分。事件是由用戶或操作系統(tǒng)產(chǎn)生的。當(dāng)我們調(diào)用應(yīng)用的 exec_() 時(shí),應(yīng)用就進(jìn)入了主循環(huán)。主循環(huán)會(huì)接受事件并且把它們發(fā)送給對(duì)象。Trolltech 引入了一個(gè)獨(dú)特的信號(hào)和槽機(jī)制。
事件是任何 GUI 程序中很重要的部分。所有 GUI 應(yīng)用都是事件驅(qū)動(dòng)的。一個(gè)應(yīng)用對(duì)其生命期產(chǎn)生的不同的事件類型做出反應(yīng)。事件是主要由應(yīng)用的用戶產(chǎn)生。但是,也可以通過其他方法產(chǎn)生,比如,網(wǎng)絡(luò)通信,窗口的管理者,計(jì)時(shí)器。在事件模型中,有三個(gè)參與者:
- 事件源(event source)
- 事件對(duì)象(event object)
- 事件目標(biāo)(event target)
event source 是那些狀態(tài)改變的對(duì)象。它產(chǎn)生事件。而 event object (Event)封裝了事件源的狀態(tài)改變。而 event target 則是需要被通知的。事件源把處理事件的任務(wù)委托給了事件目標(biāo)。
當(dāng)我們調(diào)用了應(yīng)用的 exec_() 方法,應(yīng)用就進(jìn)入主循環(huán)了。主循環(huán)接受事件然后把他們發(fā)送給對(duì)象。信號(hào)和槽用于對(duì)象間的通信。當(dāng)特定的事件發(fā)生時(shí) 信號(hào) 就被發(fā)送了。而 槽 則是任何 Python 中可調(diào)用的。當(dāng)信號(hào)發(fā)送給了這個(gè)槽,槽就被調(diào)用了。
新的 API
PyQt 4.5 引入了新的 API 用于信號(hào)和槽。
QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), self.onClicked)
這是舊式的 API 。
button.clicked.connect(self.onClicked)
新式的更接近 Python 的標(biāo)準(zhǔn)。
信號(hào)與槽
這是一個(gè)簡(jiǎn)單的例子,描述 PyQt4 中的信號(hào)和槽。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
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
last edited: October 2011
"""
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 。通過拖拽滑塊,我們就可以更改 lcd 的數(shù)字。
sld.valueChanged.connect(lcd.display)
此處,我們把 slider 的信號(hào) valueChanged 和 lcd 的槽 display 連接了起來。
sender 是發(fā)送信號(hào)的對(duì)象。 receiver 是接受信號(hào)的對(duì)象。而 slot 是回饋信號(hào)的方法。
重新實(shí)現(xiàn)事件處理句柄
在 PyQt4 中事件的處理一般通過重新實(shí)現(xiàn)事件的句柄。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ZetCode PyQt4 tutorial
In this example, we reimplement an
event handler.
author: Jan Bodnar
website: zetcode.com
last edited: October 2011
"""
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()
在我們的例子中,我們重新實(shí)現(xiàn)了 keyPressEvent() 。
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
如果我們按 escape 鍵,那么應(yīng)用就將終止。
事件發(fā)送者
有些時(shí)候,知道信號(hào)的發(fā)送者是很方便的。因此,PyQt4 有個(gè) sender() 方法。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ZetCode PyQt4 tutorial
In this example, we determine the event sender
object.
author: Jan Bodnar
website: zetcode.com
last edited: October 2011
"""
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()
這個(gè)例子中有兩個(gè)按鈕。在 buttonClicked() 方法中,我們通過調(diào)用 sender() 方法知道了哪個(gè)按鈕被點(diǎn)擊了。
btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.buttonClicked)
兩個(gè)按鈕都連接到相同的槽中。
def buttonClicked(self):
sender = self.sender()
self.statusBar().showMessange(sender.text() + " was pressed")
我們通過調(diào)用 sender() 方法知道了消息源。在狀態(tài)欄中,我們顯示了被按的按鈕的標(biāo)簽。
發(fā)送信號(hào)
由 QtCore.QObject 創(chuàng)建的對(duì)象可以發(fā)送信號(hào)。如果我們點(diǎn)擊按鈕,一個(gè) clicked() 信號(hào)就被生成。在下面的例子中我們將看到如何發(fā)送信號(hào)。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ZetCode PyQt4 tutorial
In this example, we show how to emit a
custom signal.
author: Jan Bodnar
website: zetcode.com
last edited: October 2011
"""
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()
我們創(chuàng)建了一個(gè)新的信號(hào)稱為 closeApp 。這個(gè)信號(hào)在鼠標(biāo)點(diǎn)擊時(shí)將被發(fā)送。而這個(gè)信號(hào)又和 QtGui.QMainWindow 的 close() 槽相連接。
class Communicate(QtCore.QObject):
closeApp = QtCore.pyqtSignal()
我們創(chuàng)建了基于 QtCore.QObject 的類。當(dāng)它被實(shí)例化后就創(chuàng)建了一個(gè) closeApp 信號(hào)。
self.c = Communicate()
self.c.closeApp.connect(self.close)
類 Communicate 的實(shí)例就被創(chuàng)建了。我們把 QtGui.QMainWindow 的 close() 槽連接到信號(hào) closeApp 上。
def mousePressEvent(self, event):
self.c.closeApp.emit()
當(dāng)鼠標(biāo)指針在窗口中點(diǎn)擊,信號(hào) closeApp 就被發(fā)送了。
在這個(gè)部分,我們涉及了信號(hào)與槽。
|