C++ 入門指南 4.01

單元 29 - 整合 Encrypt

-unit29-

想要在 EncryptController 中使用 Encrypt 類別 (class) ,就得將 encrypt.cpp 加入 encrypt_demo 專案 (project) 之中

Encrypt → encrypt_demo

這裡利用上個單元加入 EncryptController 類別的方式,新增 Encrypt 類別的 encrypt.cppencrypt.h 檔案後,再將 encrypt_refactor.h 的內容拷貝到 encrypt.hencrypt_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() 進行解碼外,其他都是底下資料成員的 gettersetter

private:
    QString m_userInput;
    QString m_encodeResult;
    QString m_decodeResult;
    Encrypt *encryptObject;

這裡預計把 QML 取得的 userInput 放到 m_userInput ,好讓我們可以在 C++ 程式中處理使用者輸入,然後 m_encodeResult 用來暫存編碼結果, m_decodeResult 暫存解碼結果,至於 encryptObjectEncrypt 類別的指標 (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() 需要以宣告為 constQString 型態當參數 (parameter) const 表示這個參數是一個不能被修改的常數,同時這個參數 userInput 加上 & 表示這是個參考 (reference) ,由於參考有可能可以改變原本呼叫方的值,因此這裡加上 const 宣告。

setUserInput() 內會先判斷 userInputm_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 後會發生錯誤

-qstring_problem-

這是因為 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.cppencrypt_refactor.h 的內容複製到相關檔案。
2. encryptcontroller.h 要加入 Q_OBJECTQML_ELEMENT 等設定。
3. encryptcontroller.hQ_PROPERTY 是要添加在 QML 中的屬性設定。
4. Q_INVOKABLE 標記是跟 QML 中連動的成員函數,如果不用 Q_INVOKABLE 就要放在 public slots: 宣告之下。
5. 宣告為 const 的參數不會被成員函數修改。
6. emit 標記是指發射訊號的意思。
7. 標準程式庫中的 string 跟 Qt 的 QStirng 是不同的資料型態。
問題與討論
1. 為什麼設定了 Q_PROPERTYuserInput 後,還要宣告 m_userInput
2. 為什麼 encryptObject 要宣告為指標變數?
練習
1. QML 中的 Dialog 為彈出式的對話視窗,建立一個 QtQuick 的 dialog_demo 專案,裡頭建立一個 Dialogid 設定為 dialog ,自行設定 title ,並且將 standardButtons 設定為 Dialog.Ok | Dialog.Cancel ,然後另外設定一個 Button ,在 onClicked 利用 dialog.open() 開啟對話視窗。 參考程式碼
2. QML 中的 Button 為按鈕元件,建立一個 QtQuick 的 button_demo 專案,利用 ColumnRow 放入 4 個 Button ,分別出現在第一行第一列、第二行第二列、第三行第三列、第四行第四列。 參考程式碼
3. 承上題,建立一個 QtQuick 的 colorbutton_demo 專案,將按鈕功能設定為改變其他視窗元件的背景顏色。 參考程式碼
4. 承上題,建立一個 QtQuick 的 mousearea_demo 專案,將 Button 改成 MouseAreaMouseArea 是處理滑鼠在指定視窗元件中的事件,設定 MouseAreaonClicked 改變視窗元件的顏色。 參考程式碼
5. 承上題,建立一個 QtQuick 的 calculator_demo 專案,利用更多的 Row 設計簡單計算機的外觀。 參考程式碼
6. QML 中的 Timer 可以用來計算時間,建立一個 QtQuick 的 clock_demo 專案來設計小時鐘,裡頭建立一個 Timerid 設定為 timerinterval 設定為 1000runningrepeat 都設定為 true ,然後 onTriggeredid 設定為 currentTimeText ,其 textQt.formatDateTime() 設定時間日期格式,另外要在 Component.onCompleted 設定 timer.start()參考程式碼
7. QML 中的 SwipeView 可以分頁式的呈現內容,建立一個 QtQuick 的 image_demo 專案來設計分頁式的圖片檢視器,裡頭建立 SwipeViewid 設定為 viewcurrentIndex 設定為 1 , 另外用兩個 Item 分別放圖片檔案,注意引入圖片為設定 source ,路徑字串需要用 file:/// 開頭,然後用 PageIndicator 設定頁面切換的視窗元件, id 設定為 indicatorcount 設定為 view.countcurrentIndex 設定為 view.currentIndex參考程式碼
8. 總合以上練習,建立一個 QtQuick 的 guess_demo 專案來設計猜數字遊戲的 GUI 外觀。 參考程式碼
9. 承上題,建立一個 QtQuick 的 rate_demo 專案來設計匯率換算工具的 GUI 外觀。 參考程式碼
10. 承上題,建立一個 QtQuick 的 text_demo 專案來設計文字工具的 GUI 外觀。 參考程式碼

相關教學影片

上一頁 單元 27 - 使用 QML 設計視窗外觀
回 C++ 入門指南 4.01 目錄
下一頁 單元 29 - 整合 Encrypt
回 C++ 教材
回程式語言教材首頁