2014年8月26日 星期二

C++與QML的變數傳遞 ( C++ and QML Integration )


當使用QML畫UI時,第一個碰到的問題是如何與C++溝通。

大致上分為幾個步驟:

  • 建立一個Controller操作QML,Controller必須繼承QObject,因為要使用Signal與Slot就必須做這個動作。
  • 利用QObject::connect建立View與Class的Signal與Slot。
#注意C++傳給QML時是Signal對Signal,然後QML再設定一個Signal與Slot,當然也可以直接設定Signal與Slot的方式,但這樣傳送的變數只能是QVariant型態。

<pro>
TEMPLATE = app

QT += qml quick widgets

SOURCES += main.cpp \
    controller.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Default rules for deployment.
include(deployment.pri)

HEADERS += \
    controller.h


<main.cpp>
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include "controller.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
    QObject* topLevel     = engine.rootObjects().first();
    QQuickWindow* rootWin = qobject_cast<QQuickWindow *>( topLevel );

    Controller *controller = new Controller();
    controller->initialize( rootWin );

    return app.exec();
}

void initialize(QObject *qObj)
建立C++與QML的Signal和Slot。

void updateName( QString name )
C++ 傳一個QString給QML

void setName( QString name )
接收QML傳給C++的Function

<controller.h>
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>

class Controller : public QObject
{
    Q_OBJECT
public:
    explicit Controller(QObject *parent = 0);
    void initialize( QObject* qObj );

signals:
    void updateName( QString name );

public slots:
    void setName( QString name );

private:
    QObject* viewItem;
};

#endif // CONTROLLER_H


<controller.cpp>
#include "controller.h"
#include <QDebug>

Controller::Controller(QObject *parent) :
    QObject(parent)
{
}

void Controller::initialize(QObject *qObj)
{
    this->viewItem = qObj;
    QObject::connect( viewItem, SIGNAL( qmlSetName(QString)), this, SLOT( setName(QString)) );
    QObject::connect( this, SIGNAL( updateName(QString)), viewItem, SIGNAL( qmlUpdateName(QString)) );
}

void Controller::setName(QString name)
{
    qDebug()<<"C++ : "<<name;
    emit updateName("Modified Marc");
}

signal qmlSetName( string name )
signal qmlUpdateName( string name )
QML要使用Signal時必須先宣告。

onTriggered: {
        mainWin.qmlSetName("Marc")
}
透過onTriggered事件傳送qmlSetName()給C++。

function updateMsg( data )
接收qmlSetName()的Slot。

Component.onCompleted:
{
        mainWin.qmlUpdateName.connect( updateMsg );
}
當QML初始化完成時,建立qmlSetName與updateMsg 的Signal和Slot。

<main.qml>
import QtQuick 2.2
import QtQuick.Controls 1.1

ApplicationWindow {
    id      : mainWin
    visible : true
    width   : 320
    height  : 240
    title   : qsTr("C++ and QML Integration")

    signal qmlSetName( string name )
    signal qmlUpdateName( string name )

    menuBar: MenuBar {
        Menu {
            title: qsTr("Control")
            MenuItem {
                text: qsTr("Set Name")
                onTriggered: {
                    mainWin.qmlSetName("Marc")
                }
            }
        }
    }

    Text {
        id  : txtName
        text: qsTr("C++ and QML Integration")
        anchors.centerIn: parent
    }

    function updateMsg( data ){
        txtName.text = data
        console.log( data );
    }

    Component.onCompleted:
    {
        mainWin.qmlUpdateName.connect( updateMsg );
    }
}

1 則留言: