信號與槽的總結
QT中的信號與Linux的信號對比
1)信號源
2)信號的類型
3)信號的處理方式
QT信號與Linux信號的深度對比分析
一、信號源對比
QT信號
-
用戶定義信號
:由開發者通過
signals:
關鍵字在QObject派生類中顯式聲明
class MyObject : public QObject {Q_OBJECT signals:void mySignal(int param); };
-
框架內置信號:QT框架提供的信號(如QPushButton的clicked())
-
信號觸發方式
:通過
emit
關鍵字顯式觸發
emit mySignal(42);
Linux系統信號
-
系統預定義信號:由操作系統內核預先定義(如SIGINT、SIGSEGV等)
-
硬件產生信號:如SIGSEGV(內存訪問錯誤)、SIGFPE(算術異常)
-
進程間信號
:通過kill()系統調用發送
kill(pid, SIGTERM);
二、信號類型對比
QT信號類型特征
特性 | 說明 |
---|---|
類型安全 | 編譯時檢查參數類型匹配 |
帶參數 | 可攜帶任意數量、類型的參數 |
面向對象 | 必須屬于某個QObject派生類 |
同步/異步 | 默認隊列連接(異步),可設置為直接連接(同步) |
Linux信號類型特征
特性 | 說明 |
---|---|
固定編號 | 標準信號編號1-31,實時信號34-64 |
無參數 | 僅信號編號,不能攜帶額外數據 |
進程級別 | 與特定線程/進程關聯,非面向對象 |
同步觸發 | 信號處理函數在信號產生時立即執行 |
常見Linux信號示例:
SIGINT (2):終端中斷信號(Ctrl+C)
SIGKILL (9):強制終止信號
SIGSEGV (11):無效內存訪問
SIGTERM (15):終止請求信號
三、處理方式對比
QT信號處理(信號-槽機制)
// 連接方式
QObject::connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);// 槽函數聲明
public slots:void updateValue(int newValue);**處理特點**:
- 多線程安全:自動跨線程事件隊列傳遞
- 連接類型:
- 直接連接(同步執行)
- 隊列連接(異步,接收者線程事件循環處理)
- 自動連接(默認,根據線程關系自動選擇)
- 內存管理:自動處理對象生命周期(可使用Qt::UniqueConnection)
Linux信號處理
// 信號處理函數注冊
struct sigaction sa;
sa.sa_handler = handler;
sigaction(SIGINT, &sa, NULL);void handler(int sig) {// 信號處理邏輯
}
處理特點:
- 同步執行:中斷當前執行流立即處理
- 限制嚴格:
- 信號處理函數中只能調用異步信號安全函數
- 不能使用malloc等非可重入函數
- 特殊處理:
- SIGKILL和SIGSTOP不能被捕獲或忽略
- 某些信號會導致核心轉儲(如SIGSEGV)
四、關鍵差異總結
對比維度 | QT信號 | Linux信號 |
---|---|---|
抽象級別 | 高層次面向對象機制 | 低層次操作系統機制 |
參數傳遞 | 支持復雜參數傳遞 | 僅信號編號,無參數 |
線程處理 | 自動處理跨線程通信 | 需要顯式處理線程掩碼 |
可靠性 | 可靠,不會丟失 | 非實時信號可能丟失 |
處理時機 | 通過事件循環異步處理 | 立即中斷當前執行流 |
調試支持 | 可通過QtCreator調試 | 需要gdb等系統級調試工具 |
五、實際應用場景
QT信號典型用例
- GUI事件處理(按鈕點擊、窗口關閉)
- 跨線程通信(工作線程到主線程通知)
- 模塊間解耦(觀察者模式實現)
Linux信號典型用例
- 進程控制(優雅終止服務進程)
- 異常處理(內存錯誤、算術異常捕獲)
- 進程間簡單通知(無需復雜數據傳遞)
六、高級主題
QT信號的高級特性
-
Lambda表達式連接:
connect(button, &QPushButton::clicked, [=](){qDebug() << "Button clicked"; });
-
信號轉發:
connect(obj1, &ClassA::signalA, obj2, &ClassB::signalB);
-
信號連接管理:
disconnect()
斷開連接
Linux信號的進階處理
-
信號屏蔽:
sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); pthread_sigmask(SIG_BLOCK, &set, NULL);
-
實時信號處理:
union sigval value; value.sival_int = 42; sigqueue(pid, SIGRTMIN, value); // 可攜帶少量數據
-
替代方案:更復雜的進程通信建議使用socket、管道等機制
信號槽中connect函數的使用
connect (const QObject *sender, const char * signal ,const QObject * receiver , const char * method , Qt::ConnectionType type = Qt::AutoConnection )
參數說明:
? sender:信號的發送者;
? signal:發送的信號(信號函數);
? receiver:信號的接收者;
? method:接收信號的槽函數;
? type: ?于指定關聯?式,默認的關聯?式為 Qt::AutoConnection,通常不需要?動設定。
在控件的問題上我們需要查閱的問題
內置了哪些信號,信號是何時觸發的
內置了哪些槽,槽的作用是什么
一、常見控件的內置信號
- 按鈕類控件(QPushButton等)
主要內置信號:
clicked()
:按鈕被鼠標點擊或鍵盤激活時觸發pressed()
:按鈕被按下時立即觸發released()
:按鈕被釋放時觸發toggled(bool checked)
:可切換按鈕狀態改變時觸發
// 示例:連接按鈕點擊信號
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
- 文本輸入類控件(QLineEdit, QTextEdit)
主要內置信號:
textChanged(const QString &text)
:文本內容改變時觸發textEdited(const QString &text)
:用戶編輯文本時觸發returnPressed()
:按下回車鍵時觸發editingFinished()
:編輯完成(失去焦點)時觸發
// 示例:實時響應文本變化
connect(ui->lineEdit, &QLineEdit::textChanged,[this](const QString &text){qDebug() << "Current text:" << text;});
- 選擇類控件(QComboBox, QCheckBox, QRadioButton)
主要內置信號:
currentIndexChanged(int index)
:當前選項改變時觸發currentTextChanged(const QString &text)
:當前文本改變時觸發stateChanged(int state)
:復選框/單選按鈕狀態改變時觸發
// 示例:響應下拉框選擇變化
connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),[](int index){qDebug() << "Selected index:" << index;});
二、信號觸發時機詳解
- 用戶交互觸發
- 鼠標事件:點擊、雙擊、懸停等
- 鍵盤事件:按鍵按下、釋放、輸入等
- 觸摸事件:觸摸屏交互
- 狀態變化觸發
- 值改變:如滑塊位置、進度條值等
- 焦點變化:控件獲得/失去焦點
- 可見性變化:顯示/隱藏狀態改變
- 系統事件觸發
- 定時器超時:QTimer的timeout()信號
- 網絡響應:QNetworkReply的finished()信號
- 文件系統變化:QFileSystemWatcher的fileChanged()信號
三、常見控件的內置槽函數
- 基礎功能槽
槽函數 | 作用 | 適用控件 |
---|---|---|
setText(const QString &) | 設置控件文本 | QLabel, QLineEdit等 |
clear() | 清空內容 | QLineEdit, QTextEdit等 |
setEnabled(bool) | 啟用/禁用控件 | 所有QWidget派生類 |
show() /hide() | 顯示/隱藏控件 | 所有QWidget派生類 |
// 示例:使用內置槽
connect(ui->actionClear, &QAction::triggered,ui->textEdit, &QTextEdit::clear);
- 狀態控制槽
槽函數 | 作用 | 適用控件 |
---|---|---|
setChecked(bool) | 設置選中狀態 | QCheckBox, QRadioButton |
setCurrentIndex(int) | 設置當前選項 | QComboBox, QTabWidget |
setValue(int) | 設置數值 | QProgressBar, QSlider |
// 示例:控制進度條
connect(ui->startButton, &QPushButton::clicked,[this](){ui->progressBar->setValue(0);});
四、槽函數的作用與分類
- 數據操作槽
- 數據獲取:如
text()
、value()
等 - 數據設置:如
setText()
、setValue()
等 - 數據清除:如
clear()
、reset()
等
- 狀態控制槽
- 啟用/禁用控制:
setEnabled()
、setDisabled()
- 可見性控制:
show()
、hide()
、setVisible()
- 狀態切換:
setChecked()
、toggle()
- 視圖操作槽
- 滾動控制:
scrollToTop()
、scrollToBottom()
- 縮放控制:
zoomIn()
、zoomOut()
- 選擇控制:
selectAll()
、deselect()
五、信號與槽的高級應用
- 自動連接命名槽
QT支持特定命名格式的槽函數自動連接:
// 聲明
private slots:void on_pushButton_clicked();// 實現
void MainWindow::on_pushButton_clicked() {// 無需顯式connect,自動關聯名為"pushButton"的按鈕點擊信號
}
- 信號與槽的連接類型
// 五種連接類型
Qt::AutoConnection // 自動選擇(默認)
Qt::DirectConnection // 同步直接調用
Qt::QueuedConnection // 異步隊列調用
Qt::BlockingQueuedConnection // 阻塞式隊列調用
Qt::UniqueConnection // 唯一連接(防止重復連接)
- Lambda表達式作為槽
connect(ui->pushButton, &QPushButton::clicked, [this](){// 可以直接訪問類成員ui->label->setText("Button clicked at " + QTime::currentTime().toString());
});
六、最佳實踐建議
- 信號-槽連接規范:
- 優先使用新式語法(
&Sender::signal
形式) - 避免在構造函數中連接尚未完全初始化的對象
- 優先使用新式語法(
- 資源管理:
- 使用
QPointer
管理可能被刪除的對象 - 及時斷開不再需要的連接(
disconnect
)
- 使用
- 線程安全:
- 跨線程連接使用
QueuedConnection
- 避免在不同線程間直接操作GUI控件
- 跨線程連接使用
- 性能優化:
- 高頻信號考慮節流(throttling)或防抖(debouncing)
- 大量連接時考慮使用
QSignalMapper
或lambda統一處理
自定義槽函數
本質:自定義的一個普通的成員函數
可以讓QTCreator自動生成
自定義信號
本質:成員函數
函數的定義是QT自己生成的,作為程序員只需要寫函數聲明即可
signals:自定義信號的關鍵字
emit:完成信號的發射(emit可以省略)
信號和槽也可以帶參數
發射信號的時候,把參數傳給對應的參數
信號的參數和槽的參數一致
1)類型匹配
2)個數,信號的參數要多于槽的參數
信號槽存在的意義:解耦合
代碼要達到的要求:高內聚,低耦合
具體含義為:對程序影響很小,寫代碼的時候,某個代碼的功能被集中在一起