PyQt5信號-槽機制
signal -> emit -> slot
signal.connect(slot)
signal.disconnect(slot)
信號 (singal) 可以連接無數多個槽 (slot),或者沒有連接槽也沒有問題,信號也可以連接其他的信號。
連接的基本語句形式如下: who.singal.connect(slot)
信號是 QObject 的一個屬性。只有通過 connect方法連接起來,信號-槽機制就建立起來了。類似的信號還有 disconnect 方法和emit 方法。
disconnect 就是斷開信號-槽機制,而 emit 就是激活信號。
信號都是類的一個屬性,新的信號必須繼承自 QObject,然後由 PyQt5.QtCore.pyqtSingal(在 pyqt4 下是 PyQt4.QtCore.pyqtSingal)方法創建,這個方法接受的參數中最重要的是 types 類型,比如 int, bool 之類的,你可以認為這是信號傳遞的參數類型,但實際傳遞這些參數值的是 emit 方法。然後槽實際上就是經過特殊封裝的函數,這些函數當然需要接受一些參數或者不接受參數,而這些參數具體的值傳進來的是由 emit 方法執行的,然後我們通過 who.singal.connect(slot) 這樣的形式將某個信號和某個槽連接起來, who 的信號,然後信號類自帶的連接方法,然後連接到 slot 某個函數上,在這裏隱藏的一個重要細節就是 emit 方法,比如說你定義一個新的信號,需要將點擊屏幕的具體 x,y 坐標發送出去,內置的信號-槽將這一機制都完成了,如果你自己定義的信號和槽的話,比如 pyqtSingal(int,int) ,發送給 func(x,y),具體 x 和 y 的值你需要通過 emit(x,y) 來發送。至於什麽時候發送,已經發送的 x,y 值的獲取,這應該又是另外一個信號-槽機制的細節。
1. 自定義信號
from PyQt5.QtCore import * from PyQt5.QtGui import * class FindDialog(QDialog): findNext = pyqtSignal(str, Qt.CaseSensitivity) findPrevious = pyqtSignal(str, Qt.CaseSensitivity)
2. 自定義槽
class FindDialog(QDialog): ......
@pyqtSlot() def findClicked(self): text= self.lineEdit.text() if self.caseCheckBox.isChecked(): cs = Qt.CaseSensitive else: cs = Qt.CaseInsensitive if self.backwardCheckBox.isChecked(): self.findPrevious.emit(text, cs) else: self.findNext.emit(text, cs)
3. 發射信號
class FindDialog(QDialog): ...... @pyqtSlot() def findClicked(self): ...... if self.backwardCheckBox.isChecked(): self.findPrevious.emit(text, cs) else: self.findNext.emit(text, cs)
4. 以下是完整的示例:
#!/usr/bin/env python # -*- coding:utf-8 -*- ‘‘‘ 查找對話框示例, 自定義信號槽 ‘‘‘ from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * class FindDialog(QDialog): findNext = pyqtSignal(str, Qt.CaseSensitivity) findPrevious = pyqtSignal(str, Qt.CaseSensitivity) def __init__(self, parent = None): super().__init__(parent) label = QLabel(self.tr(‘Find &what:‘)) self.lineEdit = QLineEdit() label.setBuddy(self.lineEdit) self.caseCheckBox = QCheckBox(self.tr(‘Match &case‘)) self.backwardCheckBox = QCheckBox(self.tr(‘Search &backward‘)) self.findButton = QPushButton(self.tr(‘&Find‘)) self.findButton.setDefault(True) self.findButton.setEnabled(False) closeButton = QPushButton(self.tr(‘Close‘)) self.lineEdit.textChanged.connect(self.enableFindButton) self.findButton.clicked.connect(self.findClicked) closeButton.clicked.connect(self.close) topLeftLayout = QHBoxLayout() topLeftLayout.addWidget(label) topLeftLayout.addWidget(self.lineEdit) leftLayout = QVBoxLayout() leftLayout.addLayout(topLeftLayout) leftLayout.addWidget(self.caseCheckBox) leftLayout.addWidget(self.backwardCheckBox) rightLayout = QVBoxLayout() rightLayout.addWidget(self.findButton) rightLayout.addWidget(closeButton) rightLayout.addStretch() mainLayout = QHBoxLayout() mainLayout.addLayout(leftLayout) mainLayout.addLayout(rightLayout) self.setLayout(mainLayout) self.setWindowTitle(self.tr(‘Find‘)) self.setFixedHeight(self.sizeHint().height()) def enableFindButton(self, text): self.findButton.setEnabled(bool(text)) @pyqtSlot() def findClicked(self): text = self.lineEdit.text() if self.caseCheckBox.isChecked(): cs = Qt.CaseSensitive else: cs = Qt.CaseInsensitive if self.backwardCheckBox.isChecked(): self.findPrevious.emit(text, cs) else: self.findNext.emit(text, cs) if __name__ == ‘__main__‘: import sys app = QApplication(sys.argv) findDialog = FindDialog() def find(text, cs): print(‘find:‘, text, ‘cs‘, cs) def findp(text, cs): print(‘findp:‘, text, ‘cs‘, cs) findDialog.findNext.connect(find) findDialog.findPrevious.connect(findp) findDialog.show() sys.exit(app.exec_())
d
PyQt5信號-槽機制