PyQt 中的 pyqtSignal
和 pyqtSlot
教學
在使用 PyQt5 開發 GUI 程式時,信號 (Signal) 和 槽 (Slot) 是重要的機制,用於元件之間的通訊。
PyQt 提供了 pyqtSignal
和 pyqtSlot
來自定義信號和槽,進一步實現更靈活的功能。
一、pyqtSignal
:自定義信號
pyqtSignal
是用來定義自訂信號的工具。你可以使用信號來通知其他部分程式某些事件發生了。語法
from PyQt5.QtCore import QObject, pyqtSignal
class MyObject(QObject):
my_signal = pyqtSignal([參數類型1, 參數類型2, ...])
- 信號特性:
- 可以攜帶參數。
- 需要先定義信號,然後在程式中觸發 (emit)。
- 信號可以與槽函數連接。
範例:定義和使用信號
from PyQt5.QtCore import QObject, pyqtSignal
class Worker(QObject):
# 定義一個信號,攜帶一個字符串參數
progress_signal = pyqtSignal(str)
def do_work(self):
# 當工作進行時,發出信號
for i in range(5):
self.progress_signal.emit(f"Step {i + 1} completed!")
# 創建對象
worker = Worker()
# 定義槽函數
def handle_progress(message):
print(message)
# 將信號連接到槽
worker.progress_signal.connect(handle_progress)
# 開始工作並觸發信號
worker.do_work()
輸出:
Step 1 completed!
Step 2 completed!
Step 3 completed!
Step 4 completed!
Step 5 completed!
二、pyqtSlot
:明確的槽函數
pyqtSlot
是用來定義槽函數的裝飾器。儘管 Python 的普通函數也能作為槽函數,但 pyqtSlot
能帶來一些優勢,例如:
- 提升效能:減少 Python 和 C++ 之間的邊界開銷。
- 強化類型檢查:明確指定槽函數接受的參數類型。
語法
from PyQt5.QtCore import pyqtSlot
@pyqtSlot(參數類型1, 參數類型2, ...)
def your_slot_function(...):
...
範例:使用 pyqtSlot
定義槽
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
class Worker(QObject):
progress_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
# 將信號連接到槽
self.progress_signal.connect(self.handle_progress)
@pyqtSlot(str) # 使用 pyqtSlot 裝飾器
def handle_progress(self, message):
print(f"Received message: {message}")
def do_work(self):
for i in range(3):
self.progress_signal.emit(f"Task {i + 1} done")
# 測試
worker = Worker()
worker.do_work()
輸出:
Received message: Task 1 done
Received message: Task 2 done
Received message: Task 3 done
三、綜合範例:信號與槽的完整應用
以下是一個更複雜的例子,展示信號與槽的結合用法。
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget
class MyWidget(QWidget):
# 自訂信號,帶一個字符串參數
button_clicked_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.setWindowTitle("信號與槽範例")
# 設置介面
self.label = QLabel("按下按鈕會觸發信號")
self.button = QPushButton("點我")
layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.button)
self.setLayout(layout)
# 信號連接槽
self.button.clicked.connect(self.emit_signal)
self.button_clicked_signal.connect(self.update_label)
def emit_signal(self):
# 當按鈕被點擊時,發出自訂信號
self.button_clicked_signal.emit("按鈕被按下了!")
@pyqtSlot(str) # 使用 pyqtSlot 定義槽
def update_label(self, message):
self.label.setText(message)
# 測試程式
app = QApplication([])
window = MyWidget()
window.show()
app.exec_()
解釋:
- 信號定義:
button_clicked_signal = pyqtSignal(str)
定義了一個帶字符串參數的自訂信號。
- 信號發射:
- 當按鈕被點擊時,執行
emit_signal
,發出信號。
- 當按鈕被點擊時,執行
- 槽函數:
- 使用
@pyqtSlot(str)
定義槽函數update_label
,更新介面上的標籤文字。
- 使用


四、常見問題
1. pyqtSignal
和 pyqtSlot
必須一起使用嗎?
- 不必。普通函數也能作為槽函數,但
pyqtSlot
能提供更好的效能和類型檢查。
2. 一個信號可以連接多個槽嗎?
- 可以,當信號發射時,所有連接的槽函數都會執行。
3. 槽函數可以有多個信號連接嗎?
- 可以,信號之間並不衝突。
五、優化建議
- 使用
pyqtSlot
裝飾槽函數,提升效能。 - 利用信號攜帶參數,減少不必要的全域變數。
- 清晰地命名信號與槽,增強可讀性。