版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)《QtCreator快速入門》第3版第7章Qt對(duì)象模型與容器類(3課時(shí))作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)主要內(nèi)容7.1對(duì)象模型(第1課時(shí))7.2容器類(第2課時(shí))7.3正則表達(dá)式(第3課時(shí))7.4小結(jié)(第3課時(shí))作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)7.1對(duì)象模型
標(biāo)準(zhǔn)C++對(duì)象模型可以在運(yùn)行時(shí)非常有效的支持對(duì)象范式(objectparadigm),但是它的靜態(tài)特性在一些問題領(lǐng)域中不夠靈活。圖形用戶界面編程不僅需要運(yùn)行時(shí)的高效性,還需要高度的靈活性。為此,Qt在標(biāo)準(zhǔn)C++對(duì)象模型的基礎(chǔ)上添加了一些特性,形成了自己的對(duì)象模型。這些特性有:一個(gè)強(qiáng)大的無縫對(duì)象通信機(jī)制——信號(hào)和槽(signalsandslots);可查詢和可設(shè)計(jì)的對(duì)象屬性系統(tǒng)(objectproperties);強(qiáng)大的事件和事件過濾器(eventsandeventfilters);通過上下文進(jìn)行國(guó)際化的字符串翻譯機(jī)制(stringtranslationforinternationalization);完善的定時(shí)器(timers)驅(qū)動(dòng),使得可以在一個(gè)事件驅(qū)動(dòng)的GUI中處理多個(gè)任務(wù);分層結(jié)構(gòu)的、可查詢的對(duì)象樹(objecttrees),它使用一種很自然的方式來組織對(duì)象擁有權(quán)(objectownership);守衛(wèi)指針即QPointer,它在引用對(duì)象被銷毀時(shí)自動(dòng)將其設(shè)置為0;動(dòng)態(tài)的對(duì)象轉(zhuǎn)換機(jī)制(dynamiccast);
Qt的這些特性都是在遵循標(biāo)準(zhǔn)C++規(guī)范內(nèi)實(shí)現(xiàn)的,使用這些特性都必須要繼承自QObject類。其中對(duì)象通信機(jī)制和動(dòng)態(tài)屬性系統(tǒng),還需要元對(duì)象系統(tǒng)(Meta-ObjectSystem)的支持。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)和槽信號(hào)和槽用于兩個(gè)對(duì)象之間的通信,信號(hào)和槽機(jī)制是Qt的核心特征,也是Qt不同于其他開發(fā)框架的最突出的特征。在GUI編程中,當(dāng)改變了一個(gè)部件時(shí),總希望其他部件也能了解到該變化。更一般來說,我們希望任何對(duì)象都可以和其他對(duì)象進(jìn)行通信。例如,如果用戶點(diǎn)擊了關(guān)閉按鈕,我們希望可以執(zhí)行窗口的close()函數(shù)來關(guān)閉窗口。為了實(shí)現(xiàn)對(duì)象間的通信,一些工具包中使用了回調(diào)(callback)機(jī)制,而在Qt中,使用了信號(hào)和槽來進(jìn)行對(duì)象間的通信。當(dāng)一個(gè)特殊的事情發(fā)生時(shí)便可以發(fā)射一個(gè)信號(hào),比如按鈕被單擊;而槽就是一個(gè)函數(shù),它在信號(hào)發(fā)射后被調(diào)用,來響應(yīng)這個(gè)信號(hào)。在Qt的部件類中已經(jīng)定義了一些信號(hào)和槽,但是更多的做法是子類化這個(gè)部件,然后添加自己的信號(hào)和槽來實(shí)現(xiàn)想要的功能。一個(gè)信號(hào)可以關(guān)聯(lián)到多個(gè)槽上,多個(gè)信號(hào)也可以關(guān)聯(lián)到同一個(gè)槽上,甚至,一個(gè)信號(hào)還可以關(guān)聯(lián)到另一個(gè)信號(hào)上。如果存在多個(gè)槽與某個(gè)信號(hào)相關(guān)聯(lián),那么,當(dāng)這個(gè)信號(hào)被發(fā)射時(shí),這些槽將會(huì)一個(gè)接一個(gè)地執(zhí)行,執(zhí)行順序與關(guān)聯(lián)順序相同。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)聲明一個(gè)信號(hào),例如:signals:voiddlgReturn(int);//自定義的信號(hào)聲明一個(gè)信號(hào)要使用signals關(guān)鍵字。在signals前面不能使用public、private和protected等限定符,因?yàn)橹挥卸x該信號(hào)的類及其子類才可以發(fā)射該信號(hào)。信號(hào)只用聲明,不需要也不能對(duì)它進(jìn)行定義實(shí)現(xiàn)。信號(hào)沒有返回值,只能是void類型的。只有QObject類及其子類派生的類才能使用信號(hào)和槽機(jī)制,使用信號(hào)和槽,還必須在類聲明的最開始處添加Q_OBJECT宏。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)發(fā)射信號(hào)例如:voidMyDialog::on_pushButton_clicked()//確定按鈕{intvalue=ui->spinBox->value();//獲取輸入的數(shù)值
emitdlgReturn(value);//發(fā)射信號(hào)
close();//關(guān)閉對(duì)話框}
當(dāng)單擊確定按鈕時(shí),便獲取spinBox部件中的數(shù)值,然后使用自定義的信號(hào)將其作為參數(shù)發(fā)射出去。發(fā)射一個(gè)信號(hào)要使用emit關(guān)鍵字,例如程序中發(fā)射了dlgReturn()信號(hào)。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)槽自定義槽的聲明:privateslots:voidshowValue(intvalue);實(shí)現(xiàn):voidWidget::showValue(intvalue)//自定義槽{ui->label->setText(tr("獲取的值是:%1").arg(value));}
聲明一個(gè)槽需要使用slots關(guān)鍵字。一個(gè)槽可以是private、public或者protected類型的,槽也可以被聲明為虛函數(shù),這與普通的成員函數(shù)是一樣的,也可以像調(diào)用一個(gè)普通函數(shù)一樣來調(diào)用槽。槽的最大特點(diǎn)就是可以和信號(hào)關(guān)聯(lián)。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)和槽的關(guān)聯(lián)例如:MyDialog*dlg=newMyDialog(this);connect(dlg,SIGNAL(dlgReturn(int)),this,SLOT(showValue(int)));connect()函數(shù)原型如下:boolQObject::connect(constQObject*sender,constchar*signal,constQObject*receiver,constchar*method,Qt::ConnectionTypetype=Qt::AutoConnection)它的第一個(gè)參數(shù)為發(fā)送信號(hào)的對(duì)象,例如這里的dlg;第二個(gè)參數(shù)是要發(fā)送的信號(hào),這里是SIGNAL(dlgReturn(int));第三個(gè)參數(shù)是接收信號(hào)的對(duì)象,這里是this,表明是本部件,即Widget,當(dāng)這個(gè)參數(shù)為this時(shí),也可以將這個(gè)參數(shù)省略掉,因?yàn)閏onnect()函數(shù)還有另外一個(gè)重載形式,該參數(shù)默認(rèn)為this;第四個(gè)參數(shù)是要執(zhí)行的槽,這里是SLOT(showValue(int))。對(duì)于信號(hào)和槽,必須使用SIGNAL()和SLOT()宏,它們可以將其參數(shù)轉(zhuǎn)化為constchar*類型。connect()函數(shù)的返回值為bool類型,當(dāng)關(guān)聯(lián)成功時(shí)返回true。信號(hào)和槽的參數(shù)只能有類型,不能有變量,例如寫成SLOT(showValue(intvalue))是不對(duì)的。對(duì)于信號(hào)和槽的參數(shù)問題,基本原則是信號(hào)中的參數(shù)類型要和槽中的參數(shù)類型相對(duì)應(yīng),而且信號(hào)中的參數(shù)可以多于槽中的參數(shù),但是不能反過來,如果信號(hào)中有多余的參數(shù),那么它們將被忽略。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)關(guān)聯(lián)方式connect()函數(shù)的最后一個(gè)參數(shù),它表明了關(guān)聯(lián)的方式,其默認(rèn)值是Qt::AutoConnection,這里還有其他幾個(gè)選擇,具體功能如下表所示。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)Qt5中新加的關(guān)聯(lián)形式:connect()函數(shù)另一種常用的基于函數(shù)指針的重載形式:[static]QMetaObject::ConnectionQObject::connect(constQObject*sender,PointerToMemberFunctionsignal,constQObject*receiver,PointerToMemberFunctionmethod,Qt::ConnectionTypetype=Qt::AutoConnection)
與前者最大的不同就是,指定信號(hào)和槽兩個(gè)參數(shù)時(shí)不用再使用SIGNAL()和SLOT()宏,并且槽函數(shù)不再必須是使用slots關(guān)鍵字聲明的函數(shù),而可以是任意能和信號(hào)關(guān)聯(lián)的成員函數(shù)。要使一個(gè)成員函數(shù)可以和信號(hào)關(guān)聯(lián),那么這個(gè)函數(shù)的參數(shù)數(shù)目不能超過信號(hào)的參數(shù)數(shù)目,但是并不要求該函數(shù)擁有的參數(shù)類型與信號(hào)中對(duì)應(yīng)的參數(shù)類型完全一致,只需要可以進(jìn)行隱式轉(zhuǎn)換即可。使用這種重載形式,前面程序中的關(guān)聯(lián)可以使用如下代碼代替:
connect(dlg,&MyDialog::dlgReturn,this,&Widget::showValue);
使用這種方式與前一種相比,還有一個(gè)好處就是可以在編譯時(shí)進(jìn)行檢查,信號(hào)或槽的拼寫錯(cuò)誤、槽函數(shù)參數(shù)數(shù)目多于信號(hào)的參數(shù)數(shù)目等錯(cuò)誤在編譯時(shí)就能夠被發(fā)現(xiàn)。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)使用信號(hào)和槽注意事項(xiàng)需要繼承自QObject或其子類;在類聲明的最開始處添加Q_OBJECT宏;槽中的參數(shù)的類型要和信號(hào)的參數(shù)的類型相對(duì)應(yīng),且不能比信號(hào)的參數(shù)多;信號(hào)只用聲明,沒有定義,且返回值為void類型。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)和槽自動(dòng)關(guān)聯(lián)
信號(hào)和槽還有一種自動(dòng)關(guān)聯(lián)方式,比如在設(shè)計(jì)模式直接生成的“確定”按鈕的單擊信號(hào)的槽,就是使用的這種方式:
on_pushButton_clicked()
它由“on”、部件的objectName和信號(hào)三部分組成,中間用下劃線隔開。這樣組織的名稱的槽就可以直接和信號(hào)關(guān)聯(lián),而不用再使用connect()函數(shù)。自學(xué):
如果不使用設(shè)計(jì)模式生成,自定義的信號(hào)和槽應(yīng)該如何使用自動(dòng)關(guān)聯(lián),需要注意哪些事項(xiàng)?作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)和槽的高級(jí)應(yīng)用有時(shí)希望獲得信號(hào)發(fā)送者的信息,在Qt中提供了QObject::sender()函數(shù)來返回發(fā)送該信號(hào)的對(duì)象的指針。但是如果有多個(gè)信號(hào)關(guān)聯(lián)到了同一個(gè)槽上,而在該槽中需要對(duì)每一個(gè)信號(hào)進(jìn)行不同的處理,使用上面的方法就很麻煩了。對(duì)于這種情況,便可以使用QSignalMapper類。QSignalMapper可以被叫做信號(hào)映射器,它可以實(shí)現(xiàn)對(duì)多個(gè)相同部件的相同信號(hào)進(jìn)行映射,為其添加字符串或者數(shù)值參數(shù),然后再發(fā)射出去。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)信號(hào)和槽機(jī)制的特色和優(yōu)越性信號(hào)和槽機(jī)制的特色和優(yōu)越性:信號(hào)和槽機(jī)制是類型安全的,相關(guān)聯(lián)的信號(hào)和槽的參數(shù)必須匹配;信號(hào)和槽是松耦合的,信號(hào)發(fā)送者不知道也不需要知道接受者的信息;信號(hào)和槽可以使用任意類型的任意數(shù)量的參數(shù)。
雖然信號(hào)和槽機(jī)制提供了高度的靈活性,但就其性能而言,還是慢于回調(diào)機(jī)制的。當(dāng)然,這點(diǎn)性能差異通常在一個(gè)應(yīng)用程序中是很難體現(xiàn)出來的。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)屬性系統(tǒng)Qt提供了強(qiáng)大的基于元對(duì)象系統(tǒng)的屬性系統(tǒng),可以在能夠運(yùn)行Qt的平臺(tái)上支持任意的標(biāo)準(zhǔn)C++編譯器。要聲明一個(gè)屬性,那么該類必須繼承自QObject類,而且還要在聲明前使用Q_PROPERTY()宏:Q_PROPERTY(typename
(READgetFunction[WRITEsetFunction]| MEMBERmemberName[(READgetFunction|WRITEsetFunction)])[RESETresetFunction][NOTIFYnotifySignal][REVISIONint][DESIGNABLEbool][SCRIPTABLEbool][STOREDbool][USERbool][CONSTANT][FINAL])
其中type表示屬性的類型,它可以是QVariant所支持的類型或者是用戶自定義的類型。而如果是枚舉類型,還需要使用Q_ENUMS()宏在元對(duì)象系統(tǒng)中進(jìn)行注冊(cè),這樣以后才可以使用QObject::setProperty()函數(shù)來使用該屬性。name就是屬性的名稱。READ后面是讀取該屬性的函數(shù),這個(gè)函數(shù)是必須有的,而后面帶有“[]”號(hào)的選項(xiàng)表示這些函數(shù)是可選的。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)
一個(gè)屬性類似于一個(gè)數(shù)據(jù)成員,不過添加了一些可以通過元對(duì)象系統(tǒng)訪問的附加功能:一個(gè)讀(READ)操作函數(shù)。如果MEMBER變量沒有指定,那么該函數(shù)是必須有的,它用來讀取屬性的值。這個(gè)函數(shù)一般是const類型的,它的返回值類型必須是該屬性的類型,或者是該屬性類型的指針或者引用。例如,QWidget::focus是一個(gè)只讀屬性,其READ函數(shù)是QWidget::hasFocus()。一個(gè)可選的寫(WRITE)操作函數(shù)。它用來設(shè)置屬性的值。這個(gè)函數(shù)必須只有一個(gè)參數(shù),而且它的返回值必須為空void。例如,QWidget::enabled的WRITE函數(shù)是QWidget::setEnabled()。如果沒有指定READ操作函數(shù),那么必須指定一個(gè)MEMBER變量關(guān)聯(lián),這樣會(huì)使給定的成員變量變?yōu)榭勺x寫的而不用創(chuàng)建READ和WRITE操作函數(shù)。一個(gè)可選的重置(RESET)函數(shù)。它用來將屬性恢復(fù)到一個(gè)默認(rèn)的值。這個(gè)函數(shù)不能有參數(shù),而且返回值必須為空void。例如,QWidget::cursor的RESET函數(shù)是QWidget::unsetCursor()。一個(gè)可選的通知(NOTIFY)信號(hào)。如果使用該選項(xiàng),那么需要指定類中一個(gè)已經(jīng)存在的信號(hào),每當(dāng)該屬性的值改變時(shí)都會(huì)發(fā)射該信號(hào)。如果使用MEMBER變量時(shí)指定NOTIFY信號(hào),那么信號(hào)最多只能有一個(gè)參數(shù),并且參數(shù)的類型必須與屬性的類型相同。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)一個(gè)可選的版本(REVISION)號(hào)。如果包含了該版本號(hào),它會(huì)定義屬性及其通知信號(hào)只用于特定版本的API(通常暴露給QML),如果不包含,則默認(rèn)為0。可選的DESIGNABLE表明這個(gè)屬性在GUI設(shè)計(jì)器(例如QtDesigner)的屬性編輯器中是否可見。大多數(shù)屬性的該值為true,即可見??蛇x的SCRIPTABLE表明這個(gè)屬性是否可以被腳本引擎(scriptingengine)訪問,默認(rèn)值為true。可選的STORED表明是否在當(dāng)對(duì)象的狀態(tài)被存儲(chǔ)時(shí)也必須存儲(chǔ)這個(gè)屬性的值,大部分屬性的該值為true??蛇x的USER表明這個(gè)屬性是否被設(shè)計(jì)為該類的面向用戶或者用戶可編輯的屬性。一般,每一個(gè)類中只有一個(gè)USER屬性,它的默認(rèn)值為false。例如,QAbstractButton::checked是按鈕的用戶可編輯屬性??蛇x的CONSTANT表明這個(gè)屬性的值是一個(gè)常量。對(duì)于給定的一個(gè)對(duì)象實(shí)例,每一次使用常量屬性的READ方法都必須返回相同的值,但對(duì)于類的不同的實(shí)例,這個(gè)常量可以不同。一個(gè)常量屬性不可以有WRITE方法和NOTIFY信號(hào)??蛇x的FINAL表明這個(gè)屬性不能被派生類重寫。其中的READ,WRITE和RESET函數(shù)可以被繼承,也可以是虛的(virtual),當(dāng)在多繼承時(shí),它們必須繼承自第一個(gè)父類。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)自定義屬性示例classMyClass:publicQObject{Q_OBJECTQ_PROPERTY(QStringuserNameREADgetUserNameWRITEsetUserNameNOTIFYuserNameChanged);//注冊(cè)屬性u(píng)serNamepublic:explicitMyClass(QObject*parent=0);QStringgetUserName()const//實(shí)現(xiàn)READ讀函數(shù)
{returnm_userName;}voidsetUserName(QStringuserName)//實(shí)現(xiàn)WRITE寫函數(shù)
{m_userName=userName;emituserNameChanged(userName);//當(dāng)屬性值改變時(shí)發(fā)射該信號(hào)
}signals:voiduserNameChanged(QString);//聲明NOTIFY通知消息private:QStringm_userName;//私有變量,存放userName屬性的值};作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)使用自定義的屬性:
MyClass*my=newMyClass(this);//創(chuàng)建MyClass類實(shí)例
connect(my,SIGNAL(userNameChanged(QString)),this,SLOT(userChanged(QString)));my->setUserName(“yafei”);//設(shè)置屬性的值qDebug()<<“userName:”<<my->getUserName();//輸出屬性的值//使用QObject類的setProperty()函數(shù)設(shè)置屬性的值my->setProperty("userName","linux");//輸出屬性的值,這里使用了QObject類的property()函數(shù),它返回值類型為QVariantqDebug()<<"userName:"<<my->property("userName").toString();作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)對(duì)象樹和擁有權(quán)Qt中使用對(duì)象樹(objecttree)來組織和管理所有的QObject類及其子類的對(duì)象。當(dāng)創(chuàng)建一個(gè)QObject時(shí),如果使用了其他的對(duì)象作為其父對(duì)象(parent),那么這個(gè)QObject就會(huì)被添加到父對(duì)象的children()列表中,這樣當(dāng)父對(duì)象被銷毀時(shí),這個(gè)QObject也會(huì)被銷毀。實(shí)踐表明,這個(gè)機(jī)制非常適合于管理GUI對(duì)象。例如,一個(gè)QShortcut(鍵盤快捷鍵)對(duì)象是相應(yīng)窗口的一個(gè)子對(duì)象,所以當(dāng)用戶關(guān)閉了這個(gè)窗口時(shí),這個(gè)快捷鍵也可以被銷毀。
QWidget作為能夠在屏幕上顯示的所有部件的基類,擴(kuò)展了對(duì)象間的父子關(guān)系。一個(gè)子對(duì)象一般也就是一個(gè)子部件,因?yàn)樗鼈円@示在父部件的區(qū)域之中。例如,當(dāng)關(guān)閉一個(gè)消息對(duì)話框(messagebox)后要銷毀它時(shí),消息對(duì)話框中的按鈕和標(biāo)簽也會(huì)被銷毀,這也正是我們所希望的,因?yàn)榘粹o和標(biāo)簽是消息對(duì)話框的子部件。當(dāng)然,也可以自己來銷毀一個(gè)子對(duì)象。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例自定義繼承自QPushButton的MyButton類,添加析構(gòu)函數(shù)的聲明:~MyButton();定義析構(gòu)函數(shù):MyButton::~MyButton(){qDebug()<<"deletebutton";}
這樣當(dāng)MyButton的對(duì)象被銷毀時(shí),就會(huì)輸出相應(yīng)的信息。在主窗口Widget類的構(gòu)造函數(shù)中創(chuàng)建自定義的按鈕部件:MyButton*button=newMyButton(this);//創(chuàng)建按鈕部件,指定widget為父部件button->setText(tr("button"));更改Widget類的析構(gòu)函數(shù):Widget::~Widget(){deleteui;qDebug()<<"deletewidget";}
當(dāng)Widget窗口被銷毀時(shí),將輸出信息。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)運(yùn)行程序,然后關(guān)閉窗口,在QtCreator的應(yīng)用程序輸出欄中的輸出信息為:deletewidgetdeletebutton
可以看到,當(dāng)關(guān)閉窗口后,因?yàn)樵摯翱谑琼攲哟翱冢詰?yīng)用程序要銷毀該窗口部件(如果不是頂層窗口,那么關(guān)閉時(shí)只是隱藏,不會(huì)被銷毀),而當(dāng)窗口部件銷毀時(shí)會(huì)自動(dòng)銷毀其子部件。這也就是為什么在Qt中經(jīng)常只看到new操作而看不到delete操作的原因。在main.cpp文件,其中Widget對(duì)象是建立在棧上的:Widgetw;w.show();
這樣對(duì)于對(duì)象w,在關(guān)閉程序時(shí)會(huì)被自動(dòng)銷毀。而對(duì)于Widget中的部件,如果是在堆上創(chuàng)建(使用new操作符),那么只要指定Widget為其父窗口就可以了,也不需要進(jìn)行delete操作。整個(gè)應(yīng)用程序關(guān)閉時(shí),會(huì)去銷毀w對(duì)象,而此時(shí)又會(huì)自動(dòng)銷毀它的所有子部件,這些都是Qt的對(duì)象樹所完成的。 所以,對(duì)于規(guī)范的Qt程序,要在main()函數(shù)中將主窗口部件創(chuàng)建在棧上,例如“Widgetw;”,而不要在堆上進(jìn)行創(chuàng)建(使用new操作符)。對(duì)于其他窗口部件,可以使用new操作符在堆上進(jìn)行創(chuàng)建,不過一定要指定其父部件,這樣就不需要再使用delete操作符來銷毀該對(duì)象了。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)元對(duì)象系統(tǒng)Qt中的元對(duì)象系統(tǒng)(Meta-ObjectSystem)提供了對(duì)象間通信的信號(hào)和槽機(jī)制、運(yùn)行時(shí)類型信息和動(dòng)態(tài)屬性系統(tǒng)。元對(duì)象系統(tǒng)是基于以下三個(gè)條件的:該類必須繼承自QObject類;必須在類的私有聲明區(qū)聲明Q_OBJECT宏(在類定義時(shí),如果沒有指定public或者private,則默認(rèn)為private);元對(duì)象編譯器Meta-ObjectCompiler(moc),為QObject的子類實(shí)現(xiàn)元對(duì)象特性提供必要的代碼。其中moc工具讀取一個(gè)C++源文件,如果它發(fā)現(xiàn)一個(gè)或者多個(gè)類的聲明中包含有Q_OBJECT宏,便會(huì)另外創(chuàng)建一個(gè)C++源文件(就是在項(xiàng)目目錄中的debug目錄下看到的以moc開頭的C++源文件),其中包含了為每一個(gè)類生成的元對(duì)象代碼。這些產(chǎn)生的源文件或者被包含進(jìn)類的源文件中,或者和類的實(shí)現(xiàn)同時(shí)進(jìn)行編譯和鏈接。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)
元對(duì)象系統(tǒng)主要是為了實(shí)現(xiàn)信號(hào)和槽機(jī)制才被引入的,不過除了信號(hào)和槽機(jī)制以外,元對(duì)象系統(tǒng)還提供了其他一些特性:QObject::metaObject()函數(shù)可以返回一個(gè)類的元對(duì)象,它是QMetaObject類的對(duì)象;QMetaObject::className()可以在運(yùn)行時(shí)以字符串形式返回類名,而不需要C++編輯器原生的運(yùn)行時(shí)類型信息(RTTI)的支持;QObject::inherits()函數(shù)返回一個(gè)對(duì)象是否是QObject繼承樹上一個(gè)類的實(shí)例的信息;QObject::tr()和QObject::trUtf8()進(jìn)行字符串翻譯來實(shí)現(xiàn)國(guó)際化;QObject::setProperty()和QObject::property()通過名字來動(dòng)態(tài)設(shè)置或者獲取對(duì)象屬性;QMetaObject::newInstance()構(gòu)造該類的一個(gè)新實(shí)例。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)7.2容器類
Qt庫提供了一組通用的基于模板的容器類(containerclasses)。這些容器類可以用來存儲(chǔ)指定類型的項(xiàng)目(items),例如,如果大家需要一個(gè)QString類型的可變大小的數(shù)組,那么可以使用QVector(QString)。與STL(StandardTemplateLibrary,C++的標(biāo)準(zhǔn)模板庫)中的容器類相比,Qt中的這些容器類更輕量,更安全,更容易使用。Qt的容器類簡(jiǎn)介遍歷容器通用算法QStringQByteArray和QVariant作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)Qt的容器類簡(jiǎn)介
Qt提供了一些順序容器:QList,QLinkedList,QVector,QStack和QQueue。因?yàn)檫@些容器中的數(shù)據(jù)都是一個(gè)接一個(gè)線性存儲(chǔ)的,所以稱為順序容器。對(duì)于大多數(shù)應(yīng)用程序而言,使用最多的,而且最好用的是QList,雖然它是作為一個(gè)數(shù)組列表,但是它在頭部和尾部進(jìn)行添加操作是很快速的。如果需要使用一個(gè)鏈表,那么可以使用QLinkedList;如果希望數(shù)據(jù)項(xiàng)可以占用連續(xù)的內(nèi)存空間,可以使用QVector。而QStack和QQueue作為便捷類,分別提供了后進(jìn)先出(LIFO)和先進(jìn)先出(FIFO)語義。Qt還提供了一些關(guān)聯(lián)容器:QMap,QMultiMap,QHash,QMultiHash和QSet。因?yàn)檫@些容器存儲(chǔ)的是<鍵,值>對(duì),比如QMap<Key,T>,所以稱為關(guān)聯(lián)容器。其中“Multi”容器用來方便支持一個(gè)鍵多個(gè)值的情況。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QList是一個(gè)模板類,它提供了一個(gè)列表。QList<T>實(shí)際上是一個(gè)T類型項(xiàng)目的指針數(shù)組,所以它支持基于索引的訪問,而且當(dāng)項(xiàng)目的數(shù)目小于1000時(shí),可以實(shí)現(xiàn)在列表中間進(jìn)行快速的插入操作。QList提供了很多方便的接口函數(shù)來操作列表中的項(xiàng)目,例如:插入操作insert();替換操作replace();移除操作removeAt();移動(dòng)操作move();交換操作swap();在表尾添加項(xiàng)目append();在表頭添加項(xiàng)目prepend();移除第一個(gè)項(xiàng)目removeFirst();移除最后一個(gè)項(xiàng)目removeLast();從列表中移除一項(xiàng)并獲取這個(gè)項(xiàng)目takeAt(),還有相應(yīng)的takeFirst()和takeLast();獲取一個(gè)項(xiàng)目的索引indexOf();判斷是否含有相應(yīng)的項(xiàng)目contains();獲取一個(gè)項(xiàng)目出現(xiàn)的次數(shù)count()。對(duì)于QList,可以使用“<<”操作符來向列表中插入項(xiàng)目,也可以使用“[]”操作符通過索引來訪問一個(gè)項(xiàng)目,其中項(xiàng)目是從0開始編號(hào)的。不過,對(duì)于只讀的訪問,另一種方法是使用at()函數(shù),它比“[]”操作符要快很多。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)例如:
QList<QString>list;list<<"aa"<<"bb"<<"cc";//插入項(xiàng)目
if(list[1]=="bb")list[1]="ab";list.replace(2,"bc");//將“cc”換為“bc”qDebug()<<"thelistis:";//輸出整個(gè)列表
for(inti=0;i<list.size();++i){qDebug()<<list.at(i);//現(xiàn)在列表為aaabbc}list.append("dd");//在列表尾部添加
list.prepend("mm");//在列表頭部添加
QStringstr=list.takeAt(2);//從列表中刪除第3個(gè)項(xiàng)目,并獲取它
qDebug()<<"at(2)itemis:"<<str;qDebug()<<"thelistis:";for(inti=0;i<list.size();++i){qDebug()<<list.at(i);//現(xiàn)在列表為mmaabcdd}作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)
QMap類是一個(gè)容器類,它提供了一個(gè)基于跳躍列表的字典(askip-list-baseddictionary)。QMap<Key,T>是Qt的通用容器類之一,它存儲(chǔ)(鍵,值)對(duì)并提供了與鍵相關(guān)的值的快速查找。QMap中提供了很多方便的接口函數(shù),例如:插入操作insert();獲取值value();是否包含一個(gè)鍵contains();刪除一個(gè)鍵remove();刪除一個(gè)鍵并獲取該鍵對(duì)應(yīng)的值take();清空操作clear();插入一鍵多值insertMulti()??梢允褂谩癧]”操作符插入一個(gè)鍵值對(duì)或者獲取一個(gè)鍵的值,不過當(dāng)使用該操作符獲取一個(gè)不存在的鍵的值時(shí),會(huì)默認(rèn)向map中插入該鍵,為了避免這個(gè)情況,可以使用value()函數(shù)來獲取鍵的值。當(dāng)使用value()函數(shù)時(shí),如果指定的鍵不存在,那么默認(rèn)會(huì)返回0,可以在使用該函數(shù)時(shí)提供參數(shù)來更改這個(gè)默認(rèn)返回的值。QMap默認(rèn)是一個(gè)鍵對(duì)應(yīng)一個(gè)值的,但是也可以使用insertMulti()進(jìn)行一鍵多值的插入,對(duì)于一鍵多值的情況,更方便的是使用QMap的子類QMultiMap。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)例如:
QMap<QString,int>map;map["one"]=1;//向map中插入("one",1)map["three"]=3;map.insert("seven",7);//使用insert()函數(shù)進(jìn)行插入
//獲取鍵的值,使用“[]”操作符時(shí),如果map中沒有該鍵,那么會(huì)自動(dòng)插入
intvalue1=map["six"];qDebug()<<"value1:"<<value1;qDebug()<<"contains'six'?"<<map.contains("six");//使用value()函數(shù)獲取鍵的值,這樣當(dāng)鍵不存在時(shí)不會(huì)自動(dòng)插入
intvalue2=map.value("five");qDebug()<<"value2:"<<value2;qDebug()<<"contains'five'?"<<map.contains("five");//當(dāng)鍵不存在時(shí),value()默認(rèn)返回0,這里可以設(shè)定該值,比如這里設(shè)置為9intvalue3=map.value("nine",9);qDebug()<<"value3:"<<value3;作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)嵌套和賦值容器也可以嵌套使用,例如QMap<QString,QList<int>>,這里鍵的類型是QString,而值的類型是QList<int>,需要注意,在后面的“>>”符號(hào)之間要有一個(gè)空格,不然編譯器會(huì)將它當(dāng)做“>>”操作符對(duì)待。在各種容器中所存儲(chǔ)的值的類型可以是任何的可賦值的數(shù)據(jù)類型,該類型需要有一個(gè)默認(rèn)的構(gòu)造函數(shù),一個(gè)拷貝構(gòu)造函數(shù)和一個(gè)賦值操作運(yùn)算符,像基本的類型double,指針類型,Qt的數(shù)據(jù)類型如QString、QDate、QTime等。但是QObject以及QObject的子類都不能存儲(chǔ)在容器中,不過,可以存儲(chǔ)這些類的指針,例如QList<QWidget*>。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)遍歷容器
遍歷一個(gè)容器可以使用迭代器(iterators)來完成,迭代器提供了一個(gè)統(tǒng)一的方法來訪問容器中的項(xiàng)目。Qt的容器類提供了兩種類型的迭代器:Java風(fēng)格迭代器STL風(fēng)格迭代器如果只是想按順序遍歷一個(gè)容器中的項(xiàng)目,那么還可以使用Qt的:foreach關(guān)鍵字作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)Java風(fēng)格迭代器Java風(fēng)格迭代器在使用時(shí)比STL風(fēng)格迭代器要方便很多,但是在性能上稍微弱于后者。對(duì)于每一個(gè)容器類,都有兩個(gè)Java風(fēng)格迭代器數(shù)據(jù)類型:一個(gè)提供只讀訪問,一個(gè)提供讀寫訪問。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QList示例:
QList<QString>list;list<<"A"<<"B"<<"C"<<"D";QListIterator<QString>i(list);//創(chuàng)建列表的只讀迭代器,將list作為參數(shù)
qDebug()<<"theforwardis:";while(i.hasNext())//正向遍歷列表,結(jié)果為A,B,C,DqDebug()<<i.next();qDebug()<<"thebackwardis:";while(i.hasPrevious())//反向遍歷列表,結(jié)果為D,C,B,AqDebug()<<i.previous();
這里先創(chuàng)建了一個(gè)QList列表list,然后使用list作為參數(shù)創(chuàng)建了一個(gè)列表的只讀迭代器。這時(shí),迭代器指向列表的第一個(gè)項(xiàng)目的前面(這里是指向項(xiàng)目“A”的前面)。然后使用hasNext()函數(shù)來檢查在該迭代器后面是否還有項(xiàng)目,如果還有項(xiàng)目,那么使用next()來跳過這個(gè)項(xiàng)目,next()函數(shù)會(huì)返回它所跳過的項(xiàng)目。當(dāng)正向遍歷結(jié)束后,迭代器會(huì)指向列表最后一個(gè)項(xiàng)目的后面,這時(shí)可以使用hasPrevious()和previous()來進(jìn)行反向遍歷??梢钥吹剑琂ava風(fēng)格迭代器是指向項(xiàng)目之間的,而不是直接指向項(xiàng)目。所以,迭代器或者指向容器的最前面,或者指向兩個(gè)項(xiàng)目之間,或者指向容器的最后面。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QMap示例:QMap<QString,QString>map;map.insert("Paris","France");map.insert("GuatemalaCity","Guatemala");map.insert("MexicoCity","Mexico");map.insert("Moscow","Russia");QMapIterator<QString,QString>i(map);while(i.hasNext()){i.next();qDebug()<<i.key()<<":"<<i.value();}if(i.findPrevious("Mexico"))qDebug()<<“find‘Mexico’”;//向前查找鍵的值這里在QMap中存儲(chǔ)了一些(首都,國(guó)家)鍵值對(duì),然后刪除了包含以“City”字符串結(jié)尾的鍵的項(xiàng)目。對(duì)于QMap的遍歷,可以先使用next()函數(shù),然后再使用key()和value()來獲取鍵和值的信息。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)STL風(fēng)格迭代器STL風(fēng)格迭代器兼容Qt和STL的通用算法(genericalgorithms),而且在速度上進(jìn)行了優(yōu)化。對(duì)于每一個(gè)容器類,都有兩個(gè)STL風(fēng)格迭代器類型:一個(gè)提供了只讀訪問,另一個(gè)提供了讀寫訪問。因?yàn)橹蛔x迭代器比讀寫迭代器要快很多,所以應(yīng)盡可能使用只讀迭代器。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QList示例:
QList<QString>list;list<<"A"<<"B"<<"C"<<"D";QList<QString>::iteratori;//使用讀寫迭代器
qDebug()<<"theforwardis:";for(i=list.begin();i!=list.end();++i){*i=(*i).toLower();//使用QString的toLower()函數(shù)轉(zhuǎn)換為小寫
qDebug()<<*i;//結(jié)果為a,b,c,d}qDebug()<<"thebackwardis:";while(i!=list.begin()){--i;qDebug()<<*i;//結(jié)果為d,c,b,a}QList<QString>::const_iteratorj;//使用只讀迭代器
qDebug()<<"theforwardis:";for(j=list.constBegin();j!=list.constEnd();++j)qDebug()<<*j;//結(jié)果為a,b,c,dSTL風(fēng)格迭代器的API模仿了數(shù)組的指針,例如,使用“++”操作符來向后移動(dòng)迭代器使其指向下一個(gè)項(xiàng)目;使用“*”操作符返回迭代器指向的項(xiàng)目等。需要說明的是,不同于Java風(fēng)格迭代器,STL風(fēng)格迭代器是直接指向項(xiàng)目的。其中一個(gè)容器的begin()函數(shù)返回了一個(gè)指向該容器中第一個(gè)項(xiàng)目的迭代器,end()函數(shù)也返回一個(gè)迭代器,但是這個(gè)迭代器指向該容器的最后一個(gè)項(xiàng)目的下一個(gè)假想的虛項(xiàng)目,end()標(biāo)志著一個(gè)無效的位置,當(dāng)列表為空時(shí),begin()函數(shù)等價(jià)于end()函數(shù)。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)
在STL風(fēng)格迭代器中“++”和“--”操作符即可以作為前綴(++i,--i)操作符,也可以作為后綴(i++,i--)操作符。當(dāng)作為前綴時(shí)會(huì)先修改迭代器,然后返回修改后的迭代器的一個(gè)引用;當(dāng)作為后綴時(shí),在修改迭代器以前會(huì)對(duì)其進(jìn)行復(fù)制,然后返回這個(gè)復(fù)制。如果在表達(dá)式中不會(huì)對(duì)返回值進(jìn)行處理,那么最好使用前綴操作符(++i,--i),這樣會(huì)更快一些。對(duì)于非const迭代器類型,使用一元操作符“*”獲得的返回值可以用在賦值運(yùn)算符的左側(cè)。STL風(fēng)格迭代器的常用API如下表所示。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QMap示例:QMap<QString,int>map;map.insert("one",1);map.insert("two",2);map.insert("three",3);QMap<QString,int>::const_iteratorp;qDebug()<<"theforwardis:";for(p=map.constBegin();p!=map.constEnd();++p) qDebug()<<p.key()<<":"<<p.value();//結(jié)果為(one,1),(three,3),(two,2)
這里創(chuàng)建了一個(gè)QMap,然后使用STL風(fēng)格的只讀迭代器對(duì)其進(jìn)行了遍歷,輸出了其中所有項(xiàng)目的鍵和值。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)Foreach關(guān)鍵字foreach是Qt向C++語言中添加的一個(gè)用來進(jìn)行容器的順序遍歷的關(guān)鍵字,它使用預(yù)處理器來進(jìn)行實(shí)施。例如:
QList<QString>list;list.insert(0,"A");list.insert(1,"B");list.insert(2,"C");qDebug()<<"thelistis:";foreach(QStringstr,list){//從list中獲取每一項(xiàng)
qDebug()<<str;//結(jié)果為A,B,C}QMap<QString,int>map;map.insert("first",1);map.insert("second",2);map.insert("third",3);qDebug()<<endl<<"themapis:";foreach(QStringstr,map.keys())//從map中獲取每一個(gè)鍵
qDebug()<<str<<":"<<map.value(str);//輸出鍵和對(duì)應(yīng)的值,結(jié)果為(first,1),(second,2),(third,3)作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)通用算法
在<QtAlgorithms>頭文件中,Qt提供了一些全局的模板函數(shù),這些函數(shù)是可以使用在容器上的十分常用的算法。我們可以在任何提供了STL風(fēng)格迭代器的容器類上使用這些算法,包括QList、QLinkedList、QVector、QMap和QHash。如果在目標(biāo)平臺(tái)上可以使用STL,那么可以使用STL的算法來代替Qt的這些算法,因?yàn)镾TL提供了更多的算法,而Qt只提供了其中最重要的一些算法。
作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例:QStringListlist;list<<"one"<<"two"<<"three";qDebug()<<QObject::tr("qCopy()算法:");QVector<QString>vect(3);//將list中所有項(xiàng)目復(fù)制到vect中
std:copy(list.begin(),list.end(),vect.begin());qDebug()<<vect;//結(jié)果為one,two,threeqDebug()<<endl<<QObject::tr("qEqual()算法:");//從list的開始到結(jié)束的所有項(xiàng)目與vect的開始及其后面的等數(shù)量的項(xiàng)目進(jìn)行比較,//全部相同則返回trueboolret1=std:equal(list.begin(),list.end(),vect.begin());qDebug()<<"euqal:"<<ret1;//結(jié)果為trueqDebug()<<endl<<QObject::tr("qFind()算法:");//從list中查找"two",返回第一個(gè)對(duì)應(yīng)的值的迭代器,如果沒有找到則返回end()QList<QString>::iteratori=std:find(list.begin(),list.end(),"two");qDebug()<<*i;//結(jié)果為"two"作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QStringQString類提供了一個(gè)Unicode(Unicode是一種支持大部分文字系統(tǒng)的國(guó)際字符編碼標(biāo)準(zhǔn))字符串。其實(shí)在第一個(gè)HelloWorld程序就用到了它,而幾乎所有的程序中都會(huì)使用到它。
QString存儲(chǔ)了一串QChar,而QChar提供了一個(gè)16位的Unicode4.0字符。在后臺(tái),QString使用隱式共享(implicitsharing)來減少內(nèi)存使用和避免不必要的數(shù)據(jù)拷貝,這也有助于減少存儲(chǔ)16位字符的固有開銷。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)隱式共享隱式共享(ImplicitSharing)又稱為寫時(shí)復(fù)制(copy-on-write)。Qt中很多C++類使用隱式數(shù)據(jù)共享來盡可能的提高資源使用率和盡可能的減少復(fù)制操作。使用隱式共享類作為參數(shù)傳遞是既安全又有效的,因?yàn)橹挥幸粋€(gè)指向該數(shù)據(jù)的指針被傳遞了,只有當(dāng)函數(shù)向它寫入時(shí)才會(huì)復(fù)制該數(shù)據(jù)。共享的好處是程序不需要進(jìn)行不必要的數(shù)據(jù)復(fù)制,這樣可以減少數(shù)據(jù)的拷貝和使用更少的內(nèi)存,對(duì)象也可以很容易地被分配,或者作為參數(shù)被傳遞,或者從函數(shù)被返回。隱式共享在后臺(tái)進(jìn)行,在實(shí)際編程中我們不必去關(guān)注它。Qt中主要的隱式共享類有:QByteArray、QCursor、QFont、QPixmap、QString、QUrl、QVariant和所有的容器類等等。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)例如:QPixmapp1,p2;p1.load("image.bmp");p2=p1;//p1與p2共享數(shù)據(jù)QPainterpaint;paint.begin(&p2);//p2被修改paint.drawText(0,50,"Hi");paint.end();
當(dāng)處理共享對(duì)象時(shí),有兩種復(fù)制對(duì)象的方法:深拷貝(deepcopy)和淺拷貝(shallowcopy)。深拷貝意味著復(fù)制一個(gè)對(duì)象,而淺拷貝則是復(fù)制一個(gè)引用(僅僅是一個(gè)指向共享數(shù)據(jù)塊的指針)。一個(gè)深拷貝是非常昂貴的,需要消耗很多的內(nèi)存和CPU資源;而淺拷貝則非常快速,因?yàn)樗恍枰O(shè)置一個(gè)指針和增加引用計(jì)數(shù)的值。當(dāng)隱式共享類使用“=”操作符時(shí)就是使用淺拷貝,如上面的“p2=p1;”語句。但是當(dāng)一個(gè)對(duì)象被修改時(shí),就必須進(jìn)行一次深拷貝,比如上面程序中“paint.begin(&p2);”語句要對(duì)p2進(jìn)行修改,這時(shí)就要對(duì)數(shù)據(jù)進(jìn)行深拷貝,使p2和p1指向不同的數(shù)據(jù)結(jié)構(gòu),然后將p1的引用計(jì)數(shù)設(shè)為1,p2的引用計(jì)數(shù)也設(shè)為1。一個(gè)共享類由一個(gè)指向一個(gè)共享數(shù)據(jù)塊的指針和數(shù)據(jù)組成,在共享數(shù)據(jù)塊中包含了一個(gè)引用計(jì)數(shù)。當(dāng)一個(gè)共享對(duì)象被建立時(shí),會(huì)設(shè)置引用計(jì)數(shù)為1,例如這里QPixmap類是一個(gè)隱式共享類,開始時(shí)p1和p2的引用計(jì)數(shù)都為1。每當(dāng)有新的對(duì)象引用了共享數(shù)據(jù)時(shí)引用計(jì)數(shù)都會(huì)遞增,而當(dāng)有對(duì)象不再引用這個(gè)共享數(shù)據(jù)時(shí)引用計(jì)數(shù)就會(huì)遞減,當(dāng)引用計(jì)數(shù)為0時(shí),這個(gè)共享數(shù)據(jù)就會(huì)被銷毀掉。例如這里執(zhí)行了“p2=p1;”語句后,p2便與p1共享同一個(gè)數(shù)據(jù),這時(shí)p1的引用計(jì)數(shù)為2,而p2的引用計(jì)數(shù)為0,所以p2以前指向的數(shù)據(jù)結(jié)構(gòu)將會(huì)被銷毀掉。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)編輯操作在QString中提供了多個(gè)方便的函數(shù)來操作字符串,例如:append()和prepend()分別實(shí)現(xiàn)了在字符串后面和前面添加字符串或者字符;replace()替換指定位置的多個(gè)字符;insert()在指定位置添加字符串或者字符;remove()在指定位置移除多個(gè)字符;trimmed()除去字符串兩端的空白字符,這包括‘\t’、‘\n’、‘\v’、‘\f’、‘\r’和‘’;simplified()不僅除去字符串兩端的空白字符,還將字符串中間的空白字符序列替換為一個(gè)空格;split()可以將一個(gè)字符串分割為多個(gè)子字符串的列表等等。對(duì)于一個(gè)字符串,也可以使用“[]”操作符來獲取或者修改其中的一個(gè)字符,還可以使用“+”操作符來組合兩個(gè)字符串。在QString類中一個(gè)null字符串和一個(gè)空字符串并不是完全一樣的。一個(gè)null字符串是使用QString的默認(rèn)構(gòu)造函數(shù)或者在構(gòu)造函數(shù)中傳遞了0來初始化的字符串;而一個(gè)空字符串是指大小為0的字符串。一般null字符串都是空字符串,但一個(gè)空字符串不一定是一個(gè)null字符串,在實(shí)際編程中一般使用isEmpty()來判斷一個(gè)字符串是否為空。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例:
QStringstr="hello";qDebug()<<QObject::tr("字符串大?。?)<<str.size();//大小為5str[0]=QChar('H');//將第一個(gè)字符換為‘H'qDebug()<<QObject::tr("第一個(gè)字符:")<<str[0];//結(jié)果為‘H'str.append("Qt");//向字符串后添加"Qt"str.replace(1,4,"i");//將第1個(gè)字符開始的后面4個(gè)字符替換為字符串"i"str.insert(2,"my");//在第2個(gè)字符后插入"my"qDebug()<<QObject::tr("str為:")<<str;//結(jié)果為HimyQtstr=str+"!!!";//將兩個(gè)字符串組合
qDebug()<<QObject::tr(“str為:”)<<str;//結(jié)果為HimyQt?。?!
str="hi\r\nQt!\n";qDebug()<<QObject::tr("str為:")<<str;QStringstr1=str.trimmed();//除去字符串兩端的空白字符
qDebug()<<QObject::tr("str1為:")<<str1;QStringstr2=str.simplified();//除去字符串兩端和中間多余的空白字符
qDebug()<<QObject::tr("str2為:")<<str2;//結(jié)果為hiQt!作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)查詢操作在QString中提供了right()、left()和mid()函數(shù)分別來提取一個(gè)字符串的最右面,最左面和中間的含有多個(gè)字符的子字符串;使用indexOf()函數(shù)來獲取一個(gè)字符或者子字符串在該字符串中的位置;使用at()函數(shù)可以獲取一個(gè)指定位置的字符,它比“[]”操作符要快很多,因?yàn)樗粫?huì)引起深拷貝;可以使用contains()函數(shù)來判斷該字符串是否包含一個(gè)指定的字符或者字符串;可以使用count()來獲得字符串中一個(gè)字符或者子字符串出現(xiàn)的次數(shù);而使用startsWith()和endsWidth()函數(shù)可以用來判斷該字符串是否是以一個(gè)字符或者字符串開始或者結(jié)束的;對(duì)于兩個(gè)字符串的比較,可以使用“>”和“<=”等操作符,也可以使用compare()函數(shù)。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例:qDebug()<<endl<<QObject::tr("以下是在字符串中進(jìn)行查詢的操作:")<<endl;str="yafeilinux";qDebug()<<QObject::tr("字符串為:")<<str;//執(zhí)行下面一行代碼后,結(jié)果為linuxqDebug()<<QObject::tr("包含右側(cè)5個(gè)字符的子字符串:")<<str.right(5);//執(zhí)行下面一行代碼后,結(jié)果為feiqDebug()<<QObject::tr("包含第2個(gè)字符以后3個(gè)字符的子字符串:")<<str.mid(2,3);qDebug()<<QObject::tr("'fei'的位置:")<<str.indexOf("fei");//結(jié)果為2qDebug()<<QObject::tr("str的第0個(gè)字符:")<<str.at(0);//結(jié)果為yqDebug()<<QObject::tr("str中'i'字符的個(gè)數(shù):")<<str.count('i');//結(jié)果為2//執(zhí)行下面一行代碼后,結(jié)果為trueqDebug()<<QObject::tr("str是否以”ya“開始?")<<str.startsWith("ya");作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)轉(zhuǎn)換操作QString中的toInt()、toDouble()等函數(shù)可以很方便的將字符串轉(zhuǎn)換為整型或者double型數(shù)據(jù),當(dāng)轉(zhuǎn)換成功后,它們的第一個(gè)bool型參數(shù)會(huì)為true;使用靜態(tài)函數(shù)number()可以將數(shù)值轉(zhuǎn)換為字符串,這里還可以指定要轉(zhuǎn)換為哪種進(jìn)制;使用toLower()和toUpper()函數(shù)可以分別返回字符串小寫和大寫形式的副本。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例:qDebug()<<endl<<QObject::tr("以下是字符串的轉(zhuǎn)換操作:")<<endl;str="100";qDebug()<<QObject::tr("字符串轉(zhuǎn)換為整數(shù):")<<str.toInt();//結(jié)果為100intnum=45;qDebug()<<QObject::tr("整數(shù)轉(zhuǎn)換為字符串:")<<QString::number(num);//結(jié)果為“45”str="FF";boolok;inthex=str.toInt(&ok,16);qDebug()<<"ok:"<<ok<<QObject::tr("轉(zhuǎn)換為十六進(jìn)制:")<<hex;//結(jié)果為ok:true255num=26;qDebug()<<QObject::tr("使用十六進(jìn)制將整數(shù)轉(zhuǎn)換為字符串:")<<QString::number(num,16);//結(jié)果為1astr="123.456";qDebug()<<QObject::tr("字符串轉(zhuǎn)換為浮點(diǎn)型:")<<str.toFloat();//結(jié)果為123.456str="abc";qDebug()<<QObject::tr("轉(zhuǎn)換為大寫:")<<str.toUpper();//結(jié)果為ABCstr="ABC";qDebug()<<QObject::tr("轉(zhuǎn)換為小寫:")<<str.toLower();//結(jié)果為abc作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)arg()函數(shù)示例:intage=25;QStringname="yafei";//name代替%1,age代替%2str=QString("nameis%1,ageis%2").arg(name).arg(age);//結(jié)果為nameisyafei,ageis25qDebug()<<QObject::tr("更改后的str為:")<<str;str="%1%2";qDebug()<<str.arg("%1f","hello");//結(jié)果為%1fhelloqDebug()<<str.arg("%1f").arg("hello");//結(jié)果為hellof%2str=QString("ni%1").arg("hi",5,'*');qDebug()<<QObject::tr("設(shè)置字段寬度為5,使用'*'填充:")<<str;//結(jié)果為ni***hiqrealvalue=123.456;str=QString("number:%1").arg(value,0,'f',2);qDebug()<<QObject::tr("設(shè)置小數(shù)點(diǎn)位數(shù)為兩位:")<<str;//結(jié)果為"number:123.45作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)arg()函數(shù)中的參數(shù)可以取代字符串中相應(yīng)的“%1”等標(biāo)記,在字符串中可以使用的標(biāo)記在1到99之間,arg()函數(shù)會(huì)從最小的數(shù)字開始對(duì)應(yīng),比如QString(“%5,%2,%7”).arg(“a”).arg(“b”),那么“a”會(huì)代替“%2”,“b”會(huì)代替“%5”,而“%7”會(huì)直接顯示。arg()的一種重載形式是:
arg(constQString&a1,constQString&a2),它與使用str.arg(a1).arg(a2)是相同的,不過當(dāng)參數(shù)a1中含有“%1”等標(biāo)記時(shí),兩者的效果是不同的,這個(gè)可以在前面的程序中看到。該函數(shù)的另一種重載形式為:
arg(constQString&a,intfieldWidth=0,constQChar&fillChar=QLatin1Char(‘’)),這里可以設(shè)定字段寬度,如果第一個(gè)參數(shù)a的寬度小于fieldWidth的值,那么就可以使用第三個(gè)參數(shù)設(shè)置的字符來進(jìn)行填充。這里的fieldWidth如果為正值,那么文本是右對(duì)齊的,比如前面程序中的結(jié)果為“ni***hi”。而如果為負(fù)值,那么文本是左對(duì)齊的,例如將前面的程序中的fieldWidth改為-5,那么結(jié)果就應(yīng)該是“nihi***”。arg()還有一種重載形式:
arg(doublea,intfieldWidth=0,charformat=‘g’,intprecision=-1,constQChar&fillChar=QLatin1Char(‘’)),它的第一個(gè)參數(shù)是double類型的,后面的format和precision分別可以指定其類型和精度。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QByteArrayQByteArray類提供了一個(gè)字節(jié)數(shù)組,它可以用來存儲(chǔ)原始字節(jié)(包括‘\0’)和傳統(tǒng)的以‘\0’結(jié)尾的8位字符串。使用QByteArray比使用constchar*要方便很多,在后臺(tái),它總是保證數(shù)據(jù)以一個(gè)‘\0’結(jié)尾,而且使用隱式共享來減少內(nèi)存的使用和避免不必要的數(shù)據(jù)拷貝。但是除了當(dāng)需要存儲(chǔ)原始二進(jìn)制數(shù)據(jù)或者對(duì)內(nèi)存保護(hù)要求很高(如在嵌入式Linux上)時(shí),一般都推薦使用QString,因?yàn)镼String是存儲(chǔ)16位的Unicode字符,使得在應(yīng)用程序中更容易存儲(chǔ)非ASCII和非Latin-1字符,而且QString全部使用的是Qt的API。QByteArray類擁有和QString類相似的接口函數(shù),除了arg()以外,在QByteArray中都有相同的用法。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)QVariantQVariant類像是最常見的Qt的數(shù)據(jù)類型的一個(gè)共用體(union),一個(gè)QVariant對(duì)象在一個(gè)時(shí)間只保存一個(gè)單一類型的一個(gè)單一的值(有些類型可能是多值的,比如字符串列表)??梢允褂胻oT()(T代表一種數(shù)據(jù)類型)函數(shù)來將QVariant對(duì)象轉(zhuǎn)換為T類型,并且獲取它的值。這里toT()函數(shù)會(huì)復(fù)制以前的QVariant對(duì)象,然后對(duì)其進(jìn)行轉(zhuǎn)換,所以以前的QVariant對(duì)象并不會(huì)改變。QVariant是Qt中一個(gè)很重要的類,比如前面講解屬性系統(tǒng)時(shí)提到的QObject::property()返回的就是QVariant類型的對(duì)象。作者:霍亞飛(yafeilinux)歡迎訪問Qt開源社區(qū)示例:QVariantv1(15);qDebug()<<v1.toInt();//結(jié)果為15QVariantv2(12.3);qDebug()<<v2.toFloat();//結(jié)果為12.3QVariantv3("nihao");
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年中國(guó)多孔磁芯市場(chǎng)調(diào)查研究報(bào)告
- 上海工會(huì)管理職業(yè)學(xué)院《生物微機(jī)電系統(tǒng)》2023-2024學(xué)年第一學(xué)期期末試卷
- 選擇專項(xiàng)04(構(gòu)成物質(zhì)的微粒30題)解析版-2024年中考化學(xué)常考點(diǎn)專題必殺題(深圳專用)選擇題專項(xiàng)
- 提升自信力的課程設(shè)計(jì)
- 2024年秋季小學(xué)數(shù)學(xué)北京課改版一年級(jí)【數(shù)學(xué)(北京版)】5以內(nèi)的加法-3學(xué)習(xí)任務(wù)單
- 2024年秋季小學(xué)數(shù)學(xué)北京課改版五年級(jí)【數(shù)學(xué)(北京版)】節(jié)約用水-3學(xué)習(xí)任務(wù)單
- 小兒圍手術(shù)期的護(hù)理
- 中層干部素質(zhì)提升培訓(xùn)
- 中小學(xué)體育課特色建設(shè)策略及實(shí)施路徑
- 抽樣理論課程設(shè)計(jì)
- 2024-2025學(xué)年高二上學(xué)期期末數(shù)學(xué)試卷(提高篇)(含答案)
- 2025年安全生產(chǎn)目標(biāo)實(shí)施計(jì)劃
- 福建百校2025屆高三12月聯(lián)考?xì)v史試卷(含答案解析)
- 2024年山西省建筑安全員《B證》考試題庫及答案
- 2023年益陽市安化縣招聘鄉(xiāng)鎮(zhèn)衛(wèi)生院護(hù)理人員筆試真題
- 《基于PLC的智能交通燈控制系統(tǒng)設(shè)計(jì)》10000字(論文)
- 首都經(jīng)濟(jì)貿(mào)易大學(xué)《微積分》2021-2022學(xué)年第一學(xué)期期末試卷
- 人音版音樂七年級(jí)上冊(cè)《父親的草原母親的河》課件
- 2024年度短視頻內(nèi)容創(chuàng)作服務(wù)合同3篇
- 介入治療并發(fā)癥
- 鑄牢中華民族共同體意識(shí)-形考任務(wù)1-國(guó)開(NMG)-參考資料
評(píng)論
0/150
提交評(píng)論