C++ 入門指南 4.01
單元 29 - 整合 Encrypt
想要在 EncryptController 中使用 Encrypt 類別 (class) ,就得將 encrypt.cpp 加入 encrypt_demo 專案 (project) 之中
這裡利用上個單元加入 EncryptController 類別的方式,新增 Encrypt 類別的 encrypt.cpp 及 encrypt.h 檔案後,再將 encrypt_refactor.h 的內容拷貝到 encrypt.h , encrypt_refactor.cpp 的內容拷貝到 encrypt.cpp 。
底下我們逐步說明如何整合 Encrypt 類別,首先看到 encryptcontroller.h ,如下
#ifndef ENCRYPTCONTROLLER_H #define ENCRYPTCONTROLLER_H #include <QObject> #include <QString> #include <qqml.h> #include "encrypt.h" class EncryptController : public QObject { Q_OBJECT Q_PROPERTY(QString userInput READ userInput WRITE setUserInput NOTIFY userInputChanged) QML_ELEMENT public: EncryptController(QObject *parent = nullptr); QString userInput(); void setUserInput(const QString &userInput); Q_INVOKABLE void setEncryptObject(); Q_INVOKABLE QString getEncryptObject(); Q_INVOKABLE void encodeFunction(); Q_INVOKABLE QString getEncodeResult(); Q_INVOKABLE void decodeFunction(); Q_INVOKABLE QString getDecodeResult(); signals: void userInputChanged(); private: QString m_userInput; QString m_encodeResult; QString m_decodeResult; Encrypt *encryptObject; }; #endif // ENCRYPTCONTROLLER_H
以上的版本還不是最終版本的 encryptcontroller.h ,最終版本請參考「範例程式碼」的 encryptcontroller.h 。
引入部分,增加了以下內容
#include <QString> #include <qqml.h> #include "encrypt.h"
QString 是 Qt 中的字串 (string) 型態 (type) ,基本上在 Qt 使用的字串都是 QString ,至於引入 qqml.h 是為了能讓新增的 C++ 類別能當作 QML 型態,下面則是引入 Encrypt 類別的標頭檔 (header file) 。
然後在 Q_OBJECT 底下新增這兩個設定
Q_PROPERTY(QString userInput READ userInput WRITE setUserInput NOTIFY userInputChanged) QML_ELEMENT
其中 Q_PROPERTY 為 QML 中會用到的屬性,這裡宣告為 QString 型態的 userInput ,讀取 READ 是對應到底下宣告的 userInput()
QString userInput();
userInput() 為 getter ,回傳 QString 型態的字串,寫入 WRITE 則是對應到底下宣告的 setUserInput()
void setUserInput(const QString &userInput);
setUserInput() 為 setter ,用來設定 userInput ,這一行的最後則是 NOTIFY ,對應到底下宣告的 userInputChanged()
signals: void userInputChanged();
注意這裡是放在 signals 標記之下, signals 是 Qt 專案自有的標記,這預計在文字輸入方塊發生變動的時候隨之調用 userInputChanged() 。
繼續看到底下用 Q_INVOKABLE 標記的成員函數 (member function) ,這些是會用在 QML 中的成員函數,因此要用 Q_INVOKABLE 標記
Q_INVOKABLE void setEncryptObject(); Q_INVOKABLE QString getEncryptObject(); Q_INVOKABLE void encodeFunction(); Q_INVOKABLE QString getEncodeResult(); Q_INVOKABLE void decodeFunction(); Q_INVOKABLE QString getDecodeResult();
也可以放在 public slots: 宣告 (declare) 之下,這樣不用把每個成員函數都以 Q_INVOKABLE 標記。
這些以 Q_INVOKABLE 標記的成員函數除了 encodeFunction() 進行編碼, decodeFunction() 進行解碼外,其他都是底下資料成員的 getter 或 setter
private: QString m_userInput; QString m_encodeResult; QString m_decodeResult; Encrypt *encryptObject;
這裡預計把 QML 取得的 userInput 放到 m_userInput ,好讓我們可以在 C++ 程式中處理使用者輸入,然後 m_encodeResult 用來暫存編碼結果, m_decodeResult 暫存解碼結果,至於 encryptObject 是 Encrypt 類別的指標 (pointer) ,這可以在 EncryptController 類別利用 Encrypt 類別的功能。
繼續看到實作的 encryptcontroller.cpp ,底下是 userInput() 的部分
QString EncryptController::userInput() { return m_userInput; }
以上的版本還不是最終版本的 encryptcontroller.cpp ,最終版本請參考「範例程式碼」的 encryptcontroller.cpp 。
很簡單, userInput() 就是回傳 m_userInput ,繼續看到 setUserInput()
void EncryptController::setUserInput(const QString &userInput) { if (userInput == m_userInput) return; m_userInput = userInput; emit userInputChanged(); }
setUserInput() 需要以宣告為 const 的 QString 型態當參數 (parameter) , const 表示這個參數是一個不能被修改的常數,同時這個參數 userInput 加上 & 表示這是個參考 (reference) ,由於參考有可能可以改變原本呼叫方的值,因此這裡加上 const 宣告。
setUserInput() 內會先判斷 userInput 與 m_userInput 是否相等,如果相等就不需要設定,因此直接 return
if (userInput == m_userInput) return;
反之不相等就會進行設定, 將 userInput 指派給 m_userInput ,底下 emit 也是 Qt 的標記,意思是發射訊號給 userInputChanged()
m_userInput = userInput; emit userInputChanged();
如果沒有設定 userInputChanged() ,也就是在 Q_PROPERTY 刪去 NOTIFY 的部分,這會在執行 GUI 時,重新輸入英文句子後導致 GUI 崩潰。
繼續看到 setEncryptObject()
void EncryptController::setEncryptObject() { encryptObject = new Encrypt(); }
setEncryptObject() 就是替資料成員 (data member) encryptObject 建立新的 Encrypt 物件 (object) 。
然後再看到 getEncryptObject()
QString EncryptController::getEncryptObject() { return encryptObject->get_code_array(); }
getEncryptObject() 利用 Encrypt 型態的 get_code_array() 得到密碼表字串,不過實際將這段程式碼填入 Qt Creator 後會發生錯誤
這是因為 getEncryptObject() 要求回傳的是 QString ,這裡 get_code_array() 回傳的卻是 C++ 標準程式庫 (standard library) 中的 string 型態,這個問題必須修正,程式才可以順利執行,所以下一個單元會討論如何修正這個問題。
中英文術語對照 | |
---|---|
類別 | class |
資料成員 | data member |
標頭檔 | header file |
成員函數 | member function |
物件 | object |
參數 | parameter |
指標 | pointer |
專案 | project |
參考 | reference |
標準程式庫 | standard library |
字串 | string |
型態 | type |
重點整理 |
---|
1. 整合 Encrypt 類別到 Qt 的 encrypt_demo 專案,就是在 encrypt_demo 中新增 Encrypt 類別,再將 encrypt_refactor.cpp 及 encrypt_refactor.h 的內容複製到相關檔案。 |
2. encryptcontroller.h 要加入 Q_OBJECT 、 QML_ELEMENT 等設定。 |
3. encryptcontroller.h 的 Q_PROPERTY 是要添加在 QML 中的屬性設定。 |
4. Q_INVOKABLE 標記是跟 QML 中連動的成員函數,如果不用 Q_INVOKABLE 就要放在 public slots: 宣告之下。 |
5. 宣告為 const 的參數不會被成員函數修改。 |
6. emit 標記是指發射訊號的意思。 |
7. 標準程式庫中的 string 跟 Qt 的 QStirng 是不同的資料型態。 |
問題與討論 |
---|
1. 為什麼設定了 Q_PROPERTY 的 userInput 後,還要宣告 m_userInput ? |
2. 為什麼 encryptObject 要宣告為指標變數? |
練習 |
---|
1. QML 中的 Dialog 為彈出式的對話視窗,建立一個 QtQuick 的 dialog_demo 專案,裡頭建立一個 Dialog , id 設定為 dialog ,自行設定 title ,並且將 standardButtons 設定為 Dialog.Ok | Dialog.Cancel ,然後另外設定一個 Button ,在 onClicked 利用 dialog.open() 開啟對話視窗。 參考程式碼 |
2. QML 中的 Button 為按鈕元件,建立一個 QtQuick 的 button_demo 專案,利用 Column 及 Row 放入 4 個 Button ,分別出現在第一行第一列、第二行第二列、第三行第三列、第四行第四列。 參考程式碼 |
3. 承上題,建立一個 QtQuick 的 colorbutton_demo 專案,將按鈕功能設定為改變其他視窗元件的背景顏色。 參考程式碼 |
4. 承上題,建立一個 QtQuick 的 mousearea_demo 專案,將 Button 改成 MouseArea , MouseArea 是處理滑鼠在指定視窗元件中的事件,設定 MouseArea 的 onClicked 改變視窗元件的顏色。 參考程式碼 |
5. 承上題,建立一個 QtQuick 的 calculator_demo 專案,利用更多的 Row 設計簡單計算機的外觀。 參考程式碼 |
6. QML 中的 Timer 可以用來計算時間,建立一個 QtQuick 的 clock_demo 專案來設計小時鐘,裡頭建立一個 Timer , id 設定為 timer , interval 設定為 1000 , running 及 repeat 都設定為 true ,然後 onTriggered 將 id 設定為 currentTime 的 Text ,其 text 用 Qt.formatDateTime() 設定時間日期格式,另外要在 Component.onCompleted 設定 timer.start() 。 參考程式碼 |
7. QML 中的 SwipeView 可以分頁式的呈現內容,建立一個 QtQuick 的 image_demo 專案來設計分頁式的圖片檢視器,裡頭建立 SwipeView , id 設定為 view , currentIndex 設定為 1 , 另外用兩個 Item 分別放圖片檔案,注意引入圖片為設定 source ,路徑字串需要用 file:/// 開頭,然後用 PageIndicator 設定頁面切換的視窗元件, id 設定為 indicator , count 設定為 view.count , currentIndex 設定為 view.currentIndex 。 參考程式碼 |
8. 總合以上練習,建立一個 QtQuick 的 guess_demo 專案來設計猜數字遊戲的 GUI 外觀。 參考程式碼 |
9. 承上題,建立一個 QtQuick 的 rate_demo 專案來設計匯率換算工具的 GUI 外觀。 參考程式碼 |
10. 承上題,建立一個 QtQuick 的 text_demo 專案來設計文字工具的 GUI 外觀。 參考程式碼 |
相關教學影片