當使用qt建立使用者界面時,特别是那些帶有特殊控制和特征的界面時,開發者通常需要建立新資料類型來擴充或替換qt現有的的值類型集合。
标準類型,比如:qsize、qcolor和qstring都可以被存儲到qvariant對象中,在基于qobject的類中可用作屬性的類型,并且可以在信号-槽通信時發射。
下面,我會建立一個自定義類型,并且說明如何将它內建到qt的對象模型中,以便能夠以與其他qt标準類型相同的方式被存儲。接着會展示如何注冊自定義類型,使其可以在信号槽的連接配接中使用。
<a href="#%e7%ae%80%e8%bf%b0">簡述</a>
<a href="#%e5%88%9b%e5%bb%ba%e4%b8%80%e4%b8%aa%e8%87%aa%e5%ae%9a%e4%b9%89%e7%b1%bb%e5%9e%8b">建立一個自定義類型</a>
<a href="#%e4%bd%bf%e7%94%a8qmetatype%e5%a3%b0%e6%98%8e%e7%b1%bb%e5%9e%8b">使用qmetatype聲明類型</a>
<a href="#%e5%88%9b%e5%bb%ba%e5%92%8c%e9%94%80%e6%af%81%e8%87%aa%e5%ae%9a%e4%b9%89%e5%af%b9%e8%b1%a1">建立和銷毀自定義對象</a>
<a href="#%e4%bd%bf%e7%b1%bb%e5%9e%8b%e5%8f%af%e6%89%93%e5%8d%b0">使類型可列印</a>
在開始之前,需要確定建立的這個自定義類型符合qmetatype的規定的所有要求。換句話說,它必須提供:
一個公有的預設構造函數
一個公有的拷貝構造函數
一個公有的析構函數
下面的message類的定義包含了這些成員:
這個類同時還提供了一個經常使用的構造函數,以及兩個用于擷取私有資料的共有成員函數。
message類僅需要一個合适的實作,以便可以使用。然而,如果沒有其他輔助資訊,qt類型系統将無法了解如何存儲、檢索和序列化該類的執行個體。例如:我們無法将message的值儲存到qvariant中。
qt中負責自定義類型的類是qmetatype。為了讓這個類識别該類型,當定義這個類時,需要頭檔案中使用q_declare_metatype()宏:
這樣,就可以将message的值儲存在qvariant對象中,并在以後讀取。完整代碼可參見custom type example中的示範代碼。
所述q_declare_metatype()宏同時也使得這些值可以被用作信号的參數,但是僅限于direct信号槽連接配接。為了能在信号槽機制中使用自定義類型,我們需要做一些另外的工作。
雖然上面部分中的聲明使類型可以在direct信号槽連接配接中使用,但是無法用于queued信号槽連接配接中,例如:在不同線程的對象之間所建立的連接配接。這是因為元對象系統不知道如何在運作時處理自定義類型對象的建立和銷毀操作。
為了可以在運作時建立對象,需要調用qregistermetatype()模闆函數在元對象系統中注冊此類型。隻要在使用此類型的第一次連接配接建立前調用注冊函數,該類型可被用于queued信号槽連接配接。
queued custom type example示例中在main.cpp檔案中聲明了一個block類:
這個類型後來在檔案window.cpp中被用于一個信号-槽連接配接:
如果一個沒有被注冊的類型被用于queued連接配接中,在控制台中會輸出一條警告資訊。例如:
qobject::connect: cannot queue arguments of type ‘block’ (make sure ‘block’ is registered using qregistermetatype().)
出于調試目的,使一個自定義類型可列印是非常有用的,就像下面的代碼一樣:
可以通過為此類型建立流操作符來達到目的,這通常定義在該類型的頭檔案中:
在custom type example的message類實作中,我們努力讓可列印的内容盡可能的通俗易讀:
當然,輸出到debug流的資訊是簡單還是複雜都随你的意思。需要注意的是這個函數的傳回值是qdebug對象本身,盡管它通常通過調用qdebug的成員函數maybespace()來獲得,用空白字元填充流,以使其更具可讀性。