[PyQt 教學] Part 4: Layout Management ←
回到先前的範例,一個簡單的 PushButton:#!/usr/bin/env python
import sys
from PyQt4.QtGui import *
app = QApplication(sys.argv)
button = QPushButton("&Quit")
button.show()
app.exec_()
事與願違。儘管按鈕上寫著斗大的「Quit」,猛擊幾百遍也是無動於衷。
然而其實當它被按下時,就會發出「我被按了」的訊號;只是因為沒人接收到,所以這訊號便隨風而逝瞭 QQ
為了讓 widget 間能彼此溝通,Qt 有一套 Signals & Slots 機制。看看官方的廣告:
Signals and slots are used for communication between objects. The signals and slots mechanism is a central feature of Qt and probably the part that differs most from the features provided by other frameworks.
在原本的程式碼加個一行:( code )
#!/usr/bin/env python
import sys
from PyQt4.QtGui import *
app = QApplication(sys.argv)
button = QPushButton("&Quit")
button.clicked.connect(button.close)
button.show()
app.exec_()
外在並沒有變,但是心已經變了。
新增的第 9 行:把 button 的 clicked() 這個 signal,與 button 的 close() 這個 slot 聯繫 ( connect ) 起來。
之後當 button 被按下 ( 觸發 clicked() ) 時,送出的訊號就會把自己關掉瞭 (>ω<)♪♪
( 各個 class 所擁有的 signal 與 slot,在文檔裡都有列出。本例中 QPushButton 的 clicked() signal 是繼承自 QAbstractButton,而 close() slot 是繼承自 QWidget。)
這是 PyQt 4.5 起新的 pythonic 寫法,相信不難理解。要是看過之前版本的語法,就知道那不僅是一根髮指可以帶過的了......
總結 connect 的語法:
開槍的物件.signalName.connect(中槍的物件.slotName)
Qt 的 Signals & Slots 機制是用 QObject 這個 class 來實現的 ( 它是一切 Qt objects 的 base class )。signal 和 slot 都長得像一般函式一樣,而且可透過 QObject.connect() 連接在一起 ( 舊版語法 )。Class 本身的 signal 知道自己何時會被觸發,並且自動被 emit 出去 ( 也可以手動 emit )。slot 則會完成某些事,其實就是個普普通通的函式,也許會與聯繫的 signal 夾帶的參數有關。
signal 可以和許多 slot 或普通函式連接在一起 ( 多對多關係 );也可以讓 signal 與 signal 連接,產生連鎖反應。當然啦,如果 signal emit 出去卻沒人鳥的話,最後就會蒸發彷如無物瞭 (〒3〒)
signal emitter 並不需要知道是誰中槍,對於目標型別完全不必在乎;同樣地,slot 也不需要知道是誰開槍,只要知道自己中槍了就好。這個特色提供相當大的彈性;decoupling 的優勢隨著軟體愈來愈大,會愈發明顯。
Qt 主要就是靠這套機制讓 widget 間能夠相互溝通:我的 signal 摳你的 slot,你的 signal 摳他的 slot...... 摳來摳去組織出錯綜複雜的關係,讓程式能牽一髮而動全身。理解這套機制,對於上手 Qt programming 是相當關鍵的。
最後,給出另一個常見的 signals & slots 範例:( code )
#!/usr/bin/env python
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
app = QApplication(sys.argv)
spinBox = QSpinBox()
spinBox.setPrefix("$")
spinBox.setRange(0, 100)
slider = QSlider(Qt.Horizontal)
slider.setRange(0, 100)
spinBox.valueChanged.connect(slider.setValue)
slider.valueChanged.connect(spinBox.setValue)
layout = QHBoxLayout()
layout.addWidget(spinBox)
layout.addWidget(slider)
widget = QWidget()
widget.setLayout(layout)
widget.show()
app.exec_()
其中 PyQt4.QtCore 的導入是為了使用 Qt.Horizontal 這個 enum。
剩下的就請自行解讀吧!
版主寫得很好耶~
回覆刪除最近正在學PyQt4,受益良多呢
這系列真是寫得清楚易懂,看得神清氣爽好蘇湖~QAQ
回覆刪除對於像我這種剛使用pyqt者真的非常有用 感謝您~
回覆刪除這系列文章寫的太好了, 收獲好多, 感謝萬分
回覆刪除