- PyQt 教程
- PyQt - 首頁
- PyQt - 簡介
- PyQt - 環境配置
- PyQt - Hello World
- PyQt - 主要類
- PyQt - 使用Qt Designer
- PyQt - 元物件
- PyQt 訊號與槽
- PyQt - 訊號和槽
- PyQt - 支援和訊號
- PyQt - 未繫結和已繫結訊號
- PyQt - 使用PyQtSignal建立新的訊號
- PyQt - 連線、斷開和發射訊號
- PyQt - 槽裝飾器
- PyQt - 槽連線
- PyQt 佈局
- PyQt - 佈局管理
- PyQt - QBoxLayout
- PyQt - QGridLayout
- PyQt - QFormLayout
- PyQt - QHBoxLayout
- PyQt - QVBoxLayout
- PyQt - QStackedLayout
- PyQt - QGraphicsGridLayout
- PyQt - QGraphicsAnchorLayout
- PyQt - QGraphicsLayout
- PyQt - QGraphicsLinearLayout
- PyQt 基礎部件
- PyQt - 基礎部件
- PyQt - QLabel部件
- PyQt - QLineEdit部件
- PyQt - QPushButton部件
- PyQt - QRadioButton部件
- PyQt - QCheckBox部件
- PyQt - QComboBox部件
- PyQt - QSpinBox部件
- PyQt - QMessageBox
- PyQt - QDialogButtonBox部件
- PyQt - QFontComboBox部件
- PyQt - QDoubleSpinBox部件
- PyQt - QToolBox部件
- PyQt - QDialog類
- PyQt - QMessageBox
- PyQt - 多文件介面
- PyQt - 拖放操作
- PyQt 繪圖API
- PyQt - 繪圖API
- PyQt 資料庫
- PyQt - 資料庫處理
- PyQt 核心知識
- PyQt - BrushStyle 常量
- PyQt - QClipboard
- PyQt - QPixmap類
- PyQt 有用資源
- PyQt - 快速指南
- PyQt - 有用資源
- PyQt - 討論
PyQt - 使用PyQtSignal建立新的訊號
PyQt 自動為所有 Qt 內建訊號定義訊號,但有時需要自定義訊號來簡化應用程式不同部分之間的通訊。這就是 **pyqtSignal** 幫助開發者使用 **PyQtSignal 工廠** 將新的自定義訊號定義和建立為類屬性的地方。
pyqtSignal 的語法和引數
我們可以使用 **pyqtSignal** 將新的訊號定義為類屬性,如下所示:
PyQt6.QtCore.pyqtSignal(types[, name[, revision=0[, arguments=[]]]])
在上面的語法中,傳遞給 pyqtSignals 的引數扮演著不同的角色,如下所示:
- **types** - 定義構成訊號 C++ 簽名的型別。每個型別可以是 Python 型別物件,表示 C++ 型別的字串,或定義多個訊號過載的型別引數序列。例如,int、float 等。
- **name(可選)** - 指定訊號的名稱。如果省略,則使用類屬性的名稱。
- **revision(可選)** - 指定匯出到 QML(Qt 建模語言)的訊號的修訂版。
- **arguments(可選)** - 指定匯出到 QML 的訊號引數的名稱。
定義新的訊號
PyQt 中的新訊號指定了當某些特定操作發生或某些狀態發生變化時,由物件發出的事件或條件。當發出新訊號時,連線到這些訊號的物件可以執行相應的程式碼,從而實現應用程式不同部分之間有效的通訊和互動。
訊號定義示例
from PyQt6.QtCore import QObject, pyqtSignal class Foo(QObject): # Define a signal called 'closed' with no arguments. closed = pyqtSignal() # Define a signal called 'rangeChanged' with two integer arguments. range_changed = pyqtSignal(int, int, name='rangeChanged') # Define a signal called 'valueChanged' with two overloads: int and QString. valueChanged = pyqtSignal([int], ['QString'])
定義新訊號的指南
- 新訊號只能在 QObject 的子類中定義。
- 新訊號必須是類定義的一部分,不能在類定義後動態新增。
- 使用 pyqtSignal 定義的新訊號會自動新增到類的 QMetaObject 中,使其可在 Qt Designer 和透過 QMetaObject API 訪問。
過載訊號的注意事項
當我們定義過載訊號時,即訊號包含多個訊號簽名型別,在處理沒有相應 C++ 型別的 Python 型別時,我們應該謹慎。可能存在具有不同 Python 簽名但 C++ 簽名相同的過載訊號,這會導致意外行為。
具有意外行為的過載訊號示例
class Foo(QObject): # This will cause problems because each has the same C++ signature. cautiousSignal = pyqtSignal([dict], [list])
PyQt 在內部會將 [dict] 和 [list] 都視為陣列型別,從而導致訊號的意外行為。
新的簡單訊號示例
在下面的示例中,我們定義了一個從 **QObject** 繼承的 PyQt 類 **Counter**。我們定義了一個自定義新訊號,當被呼叫時發出一個整數。increment 方法將內部 _value 屬性增加 1 並使用更新的值發出 valueChanged 訊號。建立 Counter 的例項,並將 lambda 函式連線到其 valueChanged 訊號,以便在呼叫 increment 方法時列印當前值。
from PyQt6.QtCore import QObject, pyqtSignal
class Counter(QObject):
valueChanged = pyqtSignal(int)
def __init__(self):
super().__init__()
self._value = 0
def increment(self):
self._value += 1
self.valueChanged.emit(self._value)
counter = Counter()
counter.valueChanged.connect(lambda value: print(f"Counter value: {value}"))
counter.increment()
輸出
Counter value: 1
帶有引數的自定義新訊號示例
在這個例子中,我們定義了一個從 **QObject** 繼承的 **Worker** 類。一個新的自定義訊號 **job_done** 使用 **pyqtSignal** 定義,它發出一個字串。
do_work 方法模擬工作並使用訊息發出 job_done 訊號。建立 Worker 的例項,並將 lambda 函式連線到其 job_done 訊號,在任務完成後列印工作程式的狀態。
from PyQt6.QtCore import QObject, pyqtSignal
class Worker(QObject):
job_done = pyqtSignal(str)
def do_work(self):
# Simulating some work
result = "Task completed successfully"
self.job_done.emit(result)
worker = Worker()
worker.job_done.connect(lambda message: print(f"Worker status: {message}"))
worker.do_work()
輸出
Worker status: Task completed successfully
過載新訊號示例
在這個示例中,我們使用 **QVariant** 作為訊號的型別引數,並將引數名稱指定為 'data'。發出訊號時,我們傳遞字典作為引數。
使用 **QVariant** 允許我們透過訊號在 PyQt 物件之間傳遞像字典這樣的複雜資料型別。
from PyQt6.QtCore import QObject, pyqtSignal, QVariant
class Loader(QObject):
data_loaded = pyqtSignal(QVariant, arguments=['data'])
def load_data(self):
# Simulating data loading
data_dict = {"key1": "value1", "key2": "value2"}
self.data_loaded.emit(data_dict)
loader = Loader()
loader.data_loaded.connect(lambda data: print(f"Data loaded: {data}"))
loader.load_data()
輸出
Data loaded: {'key1': 'value1', 'key2': 'value2'}