C++ 入門指南

單元 30 - QString 的問題

本書已有新版,請參考 C++ 入門指南 4.01 - 單元 30 - QString 的問題

Qt 的 QString標準程式庫 (standard library) 中的 string 雖然都以字元 (character) 為元素 (element) ,卻是不同的型態 (type)

QString ⇎ string

我們在單元 20 - 型態轉換問題介紹過基本內建型態 (primitive built-in data type) 的轉換問題,可是 QStringstring 都是類別 (class) 定義的型態,因此兩者有各自不同的成員 (member) ,編譯器 (compiler) 認為 QStringQString ,而 stringstring ,像 QString 的前綴 Q 就是標明這是 Qt 程式庫 (library) 的字串 (string) 類別。

基本上 Qt 的視窗介面無論顯示或接收都是 QString 字串,因此當我們想要把 Encrypt 的密碼表顯示在 label_display 的時候就會產生無法處理的問題。

解決這問題有兩種途徑,第一種就是回頭修改 Encrypt 類別,把密碼表從 string 改成 QString ,這樣一來,放到 label_display 或其他 Qt 視窗元件上就完完全全沒有問題了說。

這是種解決方式,聽起來還不賴!可是會讓 Encrypt 僅限於使用 Qt 程式庫,假如改天要換到另一種 GUI 程式庫的時候,就變成 QString 的地方又要全部改寫,反倒很麻煩,不是嗎?

第二種途徑則是進行型態轉換,利用 QString 提供轉換成字元陣列 (array)函數 (function) 來進行,這樣子我們需要宣告兩個新成員函數 (member function) 在 encryptwindow.hEncryptWindow 類別宣告中

QString s2q(const string &);
string q2s(const QString &);

完整程式請參考範例程式碼的 encryptwindow.h

s2q()string 型態的物件 (object) 轉換成 QString 型態,最後回傳 QString 型態的物件, q2s() 則是相反過來,兩者的參數 (parameter) 都是 const 參考 (reference) ,實作如下

// 將 string 轉換成 QString
QString EncryptWindow::s2q(const string &s) {
    return QString(QString::fromLocal8Bit(s.c_str()));
}

// 將 QString 轉換成 string
string EncryptWindow::q2s(const QString &s) {
    return string((const char *)s.toLocal8Bit());
}

完整程式請參考範例程式碼的 encryptwindow.cpp

這樣的轉換方式類似把物件轉換成字元陣列,再利用 QStringstring建構函數 (constructor) 回傳 QStringstring 型態的物件。

on_pushButton_new_clicked() 的實作就要加進 s2q() ,如下

ui->label_display->setText(s2q(e->get_code_array()));

重新執行就沒問題囉!

-qstring2-

接下來繼續實作 on_pushButton_encode_clicked()on_pushButton_decode_clicked() ,前者對使用者輸入的字串進行編碼,如下

// 按下「編碼」按鈕的事件
void EncryptWindow::on_pushButton_encode_clicked()
{
    // 取得使用者輸入的英文句子
    input_text = ui->lineEdit_input->text();
    
    // 先測試使用者是否有輸入
    if (input_text == "") {
        // 使用者沒有輸入,在 label_display 顯示提示訊息
        ui->label_display->setText("沒有輸入字串!");
    }
    else {
        // 使用者有輸入,測試使用者是否有按過「新建」按按鈕
        if (e == nullptr) {
            // 沒按過「新建」按鈕,在 label_display 顯示提示訊息
            ui->label_display->setText("沒有編碼物件!");
        }
        else {
            // 有按過「新建」按鈕,進行編碼工作並將結果顯示在 lineEdit_output
            output_text = s2q(e->ToEncode(q2s(input_text)));
            ui->lineEdit_output->setText(output_text);
            ui->label_display->setText("結果如上");
        }
    }
}

這裡針對兩種情況分別做了預防措施,第一種情況測試使用者是否有輸入,如果沒有輸入那麼從 lineEdit_input 取得的 input_text 就會是空字串,由於沒有輸入的話,進行編碼也就沒有意義,因此直接在 label_display 顯示提示訊息。

第二種是當使用者有輸入的情況,先測試使用者是否有按過 新建 按鈕,由於有按過 新建 按鈕才有建立 Encrypt 型態的資料成員 e ,也才可以實際進行編碼或解碼,因此如果 enullptr 的話就直接在 label_display 顯示提示訊息。

因此只有在使用者有輸入及有按過 新建 按鈕的情況下才會進行編碼或解碼。

至於 on_pushButton_decode_clicked()on_pushButton_encode_clicked() 非常相似,除了把 ToEncode() 換成 ToDecode() 之外

output_text = s2q(e->ToDecode(q2s(input_text)));

來執行測試看看囉!編碼結果如下

-qstring3-

解碼結果如下

-qstring3-

還不錯,接下來我們繼續實作 存檔載入 按鈕,也就是實作存檔與載入的功能。

相關教學影片

中英文術語對照
標準程式庫 standard library
字元 character
元素 element
型態 type
基本內建型態 primitive built-in data type
類別 class
成員 member
編譯器 compiler
程式庫 library
字串 string
陣列 array
函數 function
成員函數 member function
物件 object
參數 parameter
參考 reference
重點整理
1. Qt 的 QString 與標準程式庫的 string 是不同的資料型態,兩者都是以字元當元素。
2. QStringstring 的轉換方式類似先轉換成字元陣列,再由各自的建構函數回傳屬於該型態的陣列。
3. GUI 中的編碼與解碼先進行兩項預防措施,先測試使用者是否有輸入,再測試使用者是否有按過 New 按鈕。
問題與討論
1. 比較兩種解決 QStringstring 不相通的途徑,列舉各自的優點及缺點。
2. 為什麼編碼與解碼要先進行兩項預防措施?如果不做會怎麼樣嗎?
練習
1. 承接上一個單元的 guess_game 專案,實作 Guess 按鈕,所有提示訊息都顯示在下方的 Text Browser 上。
2. 承上題,除了 QStringstring 需要互相轉換外,回傳猜測紀錄的 get_times() 為整數型態,這可以用 QString 中的 static 成員函數 number() 來轉換。

上一頁 單元 29 - 整合 Encrypt
回 C++ 入門指南目錄
下一頁 單元 31 - 存檔與載入
回 C++ 教材
回程式語言教材首頁