Qt 的 QString 跟標準程式庫 (standard library) 中的 string 雖然都以字元 (character) 為元素 (element) ,卻是不同的型態 (type)
我們在單元 20 - 型態轉換問題介紹過基本內建型態 (primitive built-in data type) 的轉換問題,可是 QString 與 string 都是類別 (class) 定義的型態,因此兩者有各自不同的成員 (member) ,編譯器 (compiler) 認為 QString 是 QString ,而 string 是 string ,像 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.h 的 EncryptWindow 類別宣告中
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 。
這樣的轉換方式類似把物件轉換成字元陣列,再利用 QString 或 string 的建構函數 (constructor) 回傳 QString 或 string 型態的物件。
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 ,也才可以實際進行編碼或解碼,因此如果 e 為 NULL 的話就直接在 label_display 顯示提示訊息。
因此只有在使用者有輸入及有按過 New 按鈕的情況下才會進行編碼或解碼。
至於 on_pushButton_decode_clicked() 跟 on_pushButton_encode_clicked() 非常相似,除了把 ToEncode() 換成 ToDecode() 之外
139 | output_text = s2q(e->ToDecode(q2s(input_text))); |
來執行測試看看囉!
還不錯,接下來我們繼續實作 Save 及 Load 按鈕,也就是實作存檔與載入的功能。
中英文術語對照
標準程式庫 | standard library |
字元 | character |
元素 | element |
型態 | type |
基本內建型態 | primitive built-in data type |
類別 | class |
成員 | member |
編譯器 | compiler |
程式庫 | library |
字串 | string |
陣列 | array |
函數 | function |
成員函數 | member function |
物件 | object |
參數 | parameter |
參考 | reference |
重點整理
- Qt 的 QString 與標準程式庫的 string 是不同的資料型態,兩者都是以字元當元素。
- QString 與 string 的轉換方式類似先轉換成字元陣列,再由各自的建構函數回傳屬於該型態的陣列。
- GUI 中的編碼與解碼先進行兩項預防措施,先測試使用者是否有輸入,再測試使用者是否有按過 New 按鈕。
問題與討論
- 比較兩種解決 QString 與 string 不相通的途徑,列舉各自的優點及缺點。
- 為什麼編碼與解碼要先進行兩項預防措施?如果不做會怎麼樣嗎?
練習
- 承接上一個單元的 guess_game 專案,實作 Guess 按鈕,所有提示訊息都顯示在下方的 Text Browser 上。
- 承上題,除了 QString 與 string 需要互相轉換外,回傳猜測紀錄的 get_times() 為整數型態,這可以用 QString 中的 static 成員函數 number() 來轉換。
the end
沒有留言:
張貼留言