QT QString 很全的使用 (轉)

QString, QByteArray, 和 QVariant這三個類和容器有許多相同之處,而且在一些狀況下能夠被看成特殊的容器。 一樣,像容器,這些類使用隱式共享來優化內存和速度。html

咱們將從QString開始。 字符串被每一個GUI程序所使用,不只是用戶界面並且還有數據結構。 C++原生提供兩種字符串: 傳統的C風格以'\0'結尾的字符數組和std::string類。 與這些不一樣,QString使用16-bit Unicode值。 Unicode 包含 ASCII 和 Latin-1 這個子集和它們的普通數值。 而QString是16-bit,因此它能夠表示世界上絕大多數語言的字符。 Unicode的更多信息,請看十七章。正則表達式

當使用QString時,咱們沒必要操心如此隱祕的細節像分配足夠的內存或着是數據是'\0'結尾的。 總的來講,QString能夠被認爲是一個QChar向量。一個QString能嵌入'\0'字符。 length()函數返回整個字符串大小,包括嵌入的'\0'。算法

QString提供一個二元+操做符來鏈接兩個字符串和一個+=操做符來向一個字符串追加字符串。 由於QString在字符串的結尾處自動預分配內存,因此經過反覆追加字符來增長一個字符串是很是快的。 這是一個+和+=結合的例子:數據庫

QString str = "User: "; str += userName + "\n";數組

還有一個QString::append()函數與+=操做符有這同樣的功能:安全

str = "User: "; str.append(userName); str.append("\n");數據結構

組合字符串的一個徹底不一樣的方式是使用QString的sprintf()函數:app

str.sprintf("%s %.1f%%", "perfect competition", 100.0);函數

支持一樣的格式說明符像C++庫的sprintf()函數。 在上面的例子中,str被賦值爲 "perfect competition 100.0%"。oop

從另一個字符串或數字來構建字符串還有另一種方式,就是使用arg():

str = QString("%1 %2 (%3s-%4s)") .arg("permissive").arg("society").arg(1950).arg(1970);

在這個例子中,"%1"被"permissive"替換,"%2被"society"替換,"%3"被"1950"替換,而"%4"被 "1970"替換。 結果是"permissive society (1950s-1970s)"。 arg()重載支持各類各樣的數據類型。 某些重載有附加參數來控制域寬,數字基數,或浮點精度。 一般,arg()是比sprintf()更好的解決方案,由於它是類型安全(type-safe)的,徹底支持Unicode,而且容許translators對"%n"參數從新排序。

QString能將數字轉換爲字符串,經過使用靜態函數QString::number():

str = QString::number(59.6);

或者使用setNum()函數:

str.setNum(59.6);

逆向變換,就是將一個字符串轉換爲一個數字,使用的是toInt(), toLongLong(), toDouble(),等等。 例如:

bool ok; double d = str.toDouble(&ok);

這些函數接受一個可選的bool類型的指針並設置這個bool變量爲TRue或false,這取決於轉換成功與否。 若是轉換失敗,這些函數返回0。

一旦咱們有一個字符串,咱們常常想要提取它的一些部分。 mid()函數返回一個給定起始位置(第一個參數)和長度(第二個參數)的字串。 例如,下面的代碼在控制檯上打印"pays":[*]

[*]使用實用的qDebug() << arg語法須要包含頭文件,而qDebug("...", arg)語法在任何至少包含一個Qt頭文件的文件中可用。

QString str = "polluter pays principle"; qDebug() << str.mid(9, 4);

若是省略第二個參數,mid()返回從指定的起始位置到這個字符串結尾的子串。 例如,下面的代碼在控制檯上打印"pays principle":

QString str = "polluter pays principle"; qDebug() << str.mid(9);

還有left()和right()函數,它們也執行相似的工做。 他們倆都接受一個表示字符數量的數字,n,並返回並返回最前面或最後面的n個字符。 例如,下面的代碼在控制檯上打印"polluter principle":

QString str = "polluter pays principle"; qDebug() << str.left(8) << " " << str.right(9);

若是咱們但願找出一個字符串是否包含某個字符,字串,或正則表達式,咱們可使用QString的indexOf()函數中的一個:

QString str = "the middle bit"; int i = str.indexOf("middle");

i將被置爲4。indexOf()函數返回-1在失敗時,並接受一個可選的起始位置和大小寫敏感標誌。

若是咱們但願檢查一個字符串是不是以某物開始或結束,咱們可使用startsWith()和endsWith()函數:

if (url.startsWith("http:") && url.endsWith(".png")) ...

這個要比下面的簡單快速:

if (url.left(5) == "http:" && url.right(4) == ".png") ...

使用==操做符的字符串比較是大小寫敏感的。 若是咱們正在比較用戶級(user-visible)字符串,localeAwareCompare()常常是正確的選擇,而且若是咱們但願大小寫不敏感,咱們能夠用toUpper()或toLower()。 例如:

if (fileName.toLower() == "readme.txt") ...

若是咱們但願用一個字符串替換另外一個字符串的某一部分,能夠用replace():

QString str = "a cloudy day"; str.replace(2, 6, "sunny");

結果是"a sunny day"。 能夠改用remove()和insert():

str.remove(2, 6); str.insert(2, "sunny");

首先,咱們刪除從位置2開始的6個字符,產生一個字符串"a day"(有兩個空格),而後咱們在位置2處插入"sunny"。

有重載版本的replace(),它們能將全部出現第一個參數的地方用第二個參數替換。 例如,這是如何將全部出現"&"的地方用"&"來替換:

str.replace("&", "&");

一個常常的需求是過濾掉字符串中的空白符(如空格,製表符,和換行符)。 QString有一個函數能從字符串的兩端刪除空白符:

QString str = " BOB \t THE \nDOG \n"; qDebug() << str.trimmed();

字符串str可被描述爲:

268fig1

trimmed()返回的字符串是:

268fig2

當處理用戶輸入時,咱們常常但願將一個或多個內部空白符替換爲單個空格,另外還要過濾掉兩端的空白符。 這就是simplified()函數所作的:

QString str = " BOB \t THE \nDOG \n"; qDebug() << str.simplified();

simplified()返回的字符串是:

268fig3

一個字符串能被分紅爲一個裝有子串的QStringList,經過使用QString::split():

QString str = "polluter pays principle"; QStringList words = str.split(" ");

在上面的例子,咱們把"polluter pays principle"分紅三個子串: "polluter", "pays", 和 "principle"。 split()函數有一個可選的第三個參數(譯者注:Qt4.4版應該是第二個參數)用來決定保留(缺省)仍是丟棄空的子串。

QStringList能被組成單個的字符串,經過使用join()。 join()的參數被插入到每對被組合的字符串之間。 例如,下面展現的是如何建立單個的字符串,它由QStringList中的字符串組成,字符串之間按字母順序排序並用換行符分開:

words.sort(); str = words.join("\n");

當處理字符串時,咱們常常須要判斷一個字符串是不是空。 調用isEmpty()或檢查length()是否爲0就能夠達到目的。

在大多數狀況下,從const char *字符串到QString的轉換是自動的,例如:

str += " (1870)";

這裏咱們將一個const char *加到一個QString上,沒有任何約束。 要將一個const char *顯示轉換成一個QString,就簡單地使用一個QString cast,或者調用fromAscii()或fromLatin1()。 (See Chapter 17 for an explanation of handling literal strings in other encodings.)

要將一個QString轉換爲一個const char *,就使用toAscii()或toLatin1()。 這些函數返回一個QByteArray,它能被轉換爲一個const char *,經過使用QByteArray::data()或QByteArray::constData()。 例如:

printf("User: %s\n", str.toAscii().data());

爲了方便,Qt提供qPrintable()宏,它執行和toAscii().constData()順序相同的操做。

printf("User: %s\n", qPrintable(str));

當咱們在一個QByteArray上調用data()或constData(),返回的字符串屬於QByteArray對象全部。 這意味着咱們不用擔憂內存泄漏;Qt將會爲咱們回收內存。 另外一方面,咱們當心不能使用這個指針太長時間。若是QByteArray沒有保存在一個變量中,在語句結束時,它將會被自動刪除。

QByteArray有着與QString類似的API。 像left(), right(), mid(), toLower(), toUpper(), TRimmed(), 和 simplified()在QByteArray中和QString中相應的函數有着一樣的語義。 QByteArray對存儲純二進制數據(raw binary data)和8-bit編碼文本字符串有用。 通常地,咱們推薦使用QString來存儲文本而不是用QByteArray,由於QString支持Unicode。

爲了方便,QByteArray自動確保the "one past the last"byte老是 '\0',使得傳遞一個QByteArray給一個帶有const char *類型參數的函數時操做變得簡單。 QByteArray還支持內嵌的'\0'字符,這容許咱們用它來存儲任意二進制數據(arbitrary binary data)。

在有些狀況下,咱們須要用共一個變量存儲不一樣類型的數據。 一種處理是將數據編碼成一個QByteArray或一個QString。 例如,一個字符串能夠保存一個文本值或一個數字值以字符串形式。 這些處理是靈活的,卻抹殺了C++的好處,尤爲是類型安全和效率。 Qt提供一個更潔淨的方式來處理支持不一樣類型的變量。 QVariant。

QVariant類支持許多Qt類型的值,包括 QBrush, QColor, QCursor, QDateTime, QFont, QKeySequence, QPalette, QPen,QPixmap, QPoint, QRect, QRegion, QSize, 和QString, 和 基本的C++數值類型,像 double 和 int。 QVariant類還支持容器: QMap<qstring,qvariant>, QStringList, 和QList。

可變類型(Variants )被條目視圖類(item view classes),數據庫模塊,和QSettings所普遍使用,它容許咱們讀寫條目數據,數據庫數據,和用戶參數等任何兼容於QVariant的類型。 咱們已經看過第三章中這樣的例子,咱們傳遞了一個QRect,一個QStringList,和一對bool做爲可變類型給QSettings::setValue(),並做爲可變類型對它們解引用。

建立任意複雜的數據結構是可能的,經過用QVariant套用容器的值類型:

QMap<qstring, qvariant=""> pearMap; pearMap["Standard"] = 1.95; pearMap["Organic"] = 2.25; QMap<qstring, qvariant=""> fruitMap; fruitMap["Orange"] = 2.10; fruitMap["Pineapple"] = 3.85; fruitMap["Pear"] = pearMap;

咱們已經建立了一個map,它的鍵是字符串(產品名),它的值是浮點數(價格)或maps。 頂級map包含三個鍵: "Orange", "Pear", 和"Pineapple"。 與"Pear"鍵相關聯的值是一個map,它包含兩個鍵("Standard" 和"Organic")。 當在持有可變類型值的容器上迭代時,咱們須要用type()來檢查可變類型所持有的類型以便咱們作出適當的響應。

像這樣建立數據結構是很吸引人的,由於咱們能夠用咱們喜歡的方式組織數據。 然而QVariant的方便致使了性能和可讀性的損耗。 通常地,只要有可能,用它定義一個適當的C++類來存儲咱們的數據是值得的。

QVariant被Qt的元對象系統所使用而且所以是QtCore模塊的一部分。 不過,當咱們鏈接上QtGui模塊,QVariant能存儲GUI-related類型,如QColor, QFont, QIcon, QImage, 和QPixmap:

QIcon icon("open.png"); QVariant variant = icon;

爲了從QVariant將GUI-related類型值解引用,咱們可使用QVariant::value()模板函數像下面這樣:

QIcon icon = variant.value();

value()還用於non-GUI數據類型和QVariant之間的轉換,但實踐中咱們通常爲non-GUI類型使用to...()轉換函數(例如,toString())。

QVariant還能夠被用來保存自定義數據類型,假如它們提供一個缺省構造函數和一個拷貝構造函數。 爲了這個能工做,咱們必須首先使用Q_DECLARE_METATYPE()宏註冊類型,放在頭文件中類定義的下方:

Q_DECLARE_METATYPE(BusinessCard)

這使咱們像這樣寫代碼:

BusinessCard businessCard; QVariant variant = QVariant::fromValue(businessCard); ... if (variant.canConvert()) { BusinessCard card = variant.value(); ... }

由於編譯器的限制,這些模板函數在MSVC 6中不可用。若是你須要使用這個編譯器,用全局函數qVariantFromValue(),qVariantValue(), 和qVariantCanConvert()來代替。

若是自定義數據類型有<<和>>操做符爲了寫讀一個QDataStream,咱們能夠用qRegisterMetaTypeStreamOperators()註冊它們。 此外,這使得經過QSettings來存儲自定義數據類型的參數成爲可能。 例如:

qRegisterMetaTypeStreamOperators("BusinessCard");

這章的重點是Qt容器,以及QString, QByteArray, 和QVariant。 除了這些類,Qt還提供一些其餘的容器。 一個是QPair<t1, t2="">,它簡單地存儲兩個值,相似於std::pair<t1, t2="">。 另外一個是QBitArray,咱們將在第十九章第一節使用它。 最後是QVarLengthArray<t,prealloc>,QVector的一個底層替代品(low-level alternative)。 由於它在棧上預分配內存而且不是隱式共享,因此它的開銷要比QVector小,這使得它適合高效的循環(tight loops)。

Qt的算法,包括一些沒有在這裏提到的像qCopyBackward()和qEqual(),在Qt的文檔http://doc.trolltech.com/4.1/algorithms.html裏有描述。 Qt容器的更多信息,包括它們的時間複雜度和增加策略,參見http://doc.trolltech.com/4.1/containers.html

相關文章
相關標籤/搜索