以下內容為本人的著作,如需要轉載,請宣告原文連結 微信公眾號「englyf」https://www.cnblogs.com/englyf/p/16748191.html
如果面試過程中,面試官想了解你對 Qt 的理解有多少,少不了會涉及到訊號槽這一塊,畢竟這是 Qt 最經典的一項技術。
剛開筆,我可能有點狂妄了。
訊號槽,分為兩部分,訊號和對訊號響應的槽函數。在視覺化開發過程中,無論你用 QWidget 還是 QtQuick 都可以運用到訊號槽。QtQuick 是目前 Qt 公司主推的視覺化框架了,當然不會缺失對訊號槽的支援。
QtQuick 的模組提供了豐富的預定義訊號,當然也允許使用者自定義訊號。
下面就斗膽總結一下在 QML 中訊號槽的使用。
這些訊號都是Qt庫裡已經預定義好了的,為了使用這些訊號,我們需要的是匯入型別所在模組和定義響應過程即可。
上來就手掰一個栗子:比如,為了響應 MouseArea 的 clicked 訊號,僅需要在 MouseArea 型別物件宣告中新增以下形式的語句即可:
onClicked: {
// do something ....
}
on後邊緊跟著的訊號名字 clicked 必須首字母大寫。冒號後邊如果僅是單語句,可以不用大括號{},多語句結尾可以新增分號;
結尾。
提醒一下,這種對訊號槽的使用方式,適用於訊號所屬物件的內部。因為這裡邊其實是包含了隱式的連線(訊號和槽),在訊號 signal 所屬物件的內部直接宣告槽函數。
槽函數宣告,一般形式如下:
on<Signal>: {
// do something ....
}
signal 首字母要大寫。
假設宣告了一自定義屬性 property,當這個屬性被修改後,QML 引擎會發射形式如下的訊號
<property>Changed
可新增以下形式語句響應這個屬性的變化:
on<Property>Changed: {
// do something ....
}
在宣告響應時,屬性名 property 同樣需要首字母大寫。
無論是自定義的屬性,還是預定義的屬性,變化時引擎都會發射訊號,這些訊號響應的形式和上面訊號的類似,只不過需要多加個 Changed
。
簡單點理解,QML 引擎會自動在 QML 檔案裡宣告的物件中附加一個 Component 物件。當 QML 檔案定義的頂層物件載入完成時,會觸發 Component 物件的 completed 訊號,為了響應此訊號,可以新增以下形式語句:
Component.onCompleted: {
// do something ....
}
關於 Component 更多資訊可以參考
https://doc.qt.io/qt-6/qml-qtqml-component.html
大多數時候,定義的 QML 物件都會需要在其中新增或多或少的自定義訊號,同時也會需要定義相應的響應。
用以下形式宣告自定義的訊號
signal <name>[([<type> <parameter name>[, ...]])]
一般視覺化的自定義的 QML 物件都會基於 Item 或者 Rectangle 來做擴充套件,包括新增自定義訊號以及其它必要的功能等,其實這個過程也相當於對原有的型別做了派生(參考C++的習慣)。
Rectangle {
id: root
signal mysignal(int x, int y)
MouseArea {
anchors.fill: parent
onPressed: root.mysignal(mouse.x, mouse.y)
}
}
上面程式碼中,Rectangle 物件定義了訊號 mysignal,帶有整形引數x和y。然後新增了針對滑鼠區域定義的元件 MouseArea,在其中通過訊號槽去觸發父物件的自定義訊號 mysignal。
MouseArea 屬於預定義型別,pressed 訊號自帶引數 mouse。更多資訊可以參考下面的連結:
https://doc.qt.io/qt-6/qml-qtquick-mousearea.html
自定義訊號的處理形式和預定義訊號一致,參考上面預定義訊號的響應方法。
關於 connect,簡單的說,就是用於針對具體訊號指定響應的方法或者觸發的下一個訊號。囉嗦點來講,一個訊號被觸發了,那麼它可以指定響應的方法,也可以指定觸發下一個訊號形成訊號的連鎖反應,這個過程就通過 connect 來指定。
如果你熟悉 Qt, 應該對 C++ 的 QObject::connect 方法不陌生。和 C++ 部分類似,QML 中也有 connect 方法,可以連線任意的(包括多個)訊號和方法,但是 QML 的 connect 更靈活而且呼叫方式不太一樣。不一樣的是,C++ 中 QObject::connect 是靜態方法,而 QML 的 connect 由訊號提供。參考以下形式:
signal.connect(signal / function_name)
要注意一下,QML 物件的訊號必須通過物件來參照。
看個例子:
Rectangle {
id: root
signal mySignal()
// 訊號響應處理
onMySignal: console.log("clicked connect mySignal")
// 普通方法
function slt_clicked() {
console.log("clicked connect slt_clicked");
}
Component.onCompleted: {
mousearea.clicked.connect(slt_clicked);
mousearea.clicked.connect(mySignal);
}
MouseArea {
id: mousearea
anchors.fill: parent
}
}
通過上面的程式碼可知,在參照的元件 Component 的訊號 completed 的響應中,通過另一個元件 mousearea 的訊號 ( clicked ) 呼叫 connect 連線父元件的函數 slt_clicked 和訊號 mySignal。
如果訊號 clicked 帶有引數,那麼被連線的方法 ( slt_clicked ) 和訊號 ( mySignal ) 也應該有同樣數目的引數。
當 MouseArea 元件的訊號 clicked 被觸發後,可以看到下面的輸出:
clicked connect slt_clicked
clicked connect mySignal
當然,如果連線不再需要,那麼 disconnect 也是不能缺少的。disconnect 的作用和 connect 相反,專用於解綁已有連線,也是通過訊號呼叫。
Rectangle {
id: relay
// ... 省略
function removeSignal() {
mousearea.clicked.disconnect(slt_clicked);
mousearea.clicked.disconnect(mySignal);
}
}
QtQuick 框架提供了一個超級好用的型別:Connections,它可以用於響應任意物件的訊號(官方說法是generalized)。
大多數情況下,用於連線其它 QML 檔案中定義的物件的訊號,具體需要指定訊號所屬物件的 id。參考以下形式:
import QtQml
Connections {
target: object_id
onSignal: {
// do something ....
}
}
target 屬性用於指定響應訊號所屬物件的 id。
好了,暫時介紹到這裡,下回見......