C++ 入門指南 V2.00 - 單元 30 - QString 的問題




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



我們在單元 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 類別宣告中


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

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

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


024 // 將 string 轉換成 QString
025 QString EncryptWindow::s2q(const string &s) {
026    return QString(QString::fromLocal8Bit(s.c_str()));
027 }
028
029  // 將 QString 轉換成 string
030 string EncryptWindow::q2s(const QString &s) {
031    return string((const char *)s.toLocal8Bit());
032 }

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

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

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


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

重新執行就沒問題囉!



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


094 // 按下 Encode 按鈕的事件
095 void EncryptWindow::on_pushButton_encode_clicked()
096 {
097    // 取得使用者輸入的英文句子
098    input_text = ui->lineEdit_input->text();
099
100    // 先測試使用者是否有輸入
101    if (input_text == ""){
102       // 使用者沒有輸入,在 label_display 顯示提示訊息
103       ui->label_display->setText("No input string!!");
104    }
105    else {
106       // 使用者有輸入,測試使用者是否有按過 New 按鈕
107       if (e == NULL) {
108          // 沒按過 New 按鈕,在 label_display 顯示提示訊息
109          ui->label_display->setText("No Encrypt object!!");
110       }
111       else {
112          // 有按過 New 按鈕,進行編碼工作並將結果顯示在 lineEdit_output
113          output_text = s2q(e->ToEncode(q2s(input_text)));
114          ui->lineEdit_output->setText(output_text);
115          ui->label_display->setText("The result is above.");
116       }
117    }
118 }

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


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


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


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


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

來執行測試看看囉!



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


中英文術語對照


標準程式庫 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() 來轉換。

the end

沒有留言: