Integrate C++ and QML. Qt 5.4

hekri picture hekri · Dec 13, 2014 · Viewed 8k times · Source

I was reading the Qt documentation for the past couple of hours trying to figure out a way to make a UI created with Qt Quick UI (QML) communicate (interact) with C++ code (functions... etc.).

I've read the 5 or 6 similar questions on here to but I'm kind of confused, I have problems figuring out where to start or what to do first. I'd appreciate it a lot if someone could take the time and list the steps needed to make this work.

What i've done so far. I tried doing ...>add new Item> C++ class but I failed with an error saying:" failed to add one or more files to project"> It seems like the files (.. .cpp and .h) are created, they were in the folder where the other project files were but not included in the project. What I wanna do is just something simple like changing the text of the textedit through a C++ function or any other way possible.

//Test.qml (main.qml)

    import QtQuick 2.1
    import QtQuick.Window 2.0

Rectangle {
     id: rootRect
    width: Screen.width/2
    height: Screen.height/2
    color: "gray"


    Button{}

    Rectangle{
        id: textField
        width: 120
        height: 40
        color: "white"
        x:274; y: 61
        border.color: "blue"
        border.width: 4
        radius: 2

    }

    TextEdit {

        id: display
        x: 274
        y: 61
        width: 80
        height: 20
        text: qsTr("Text Edit")
        font.pixelSize: 22
        color: "black"
        anchors.centerIn: textField

    }

    Rectangle{
        id: inputField
        width: textField.width
        height: textField.height
        border.color: "green"
        border.width: 3
        color: "white"
        x: 140; y: 61
    }

    TextEdit{
        id: input
        color: "red"
        font.pixelSize: 30
        anchors.centerIn: inputField
        text: "Some Text"


    }

}

//Button.cpl

import QtQuick 2.0
import QtQuick.Window 2.0


Item {

    property string defaultText: "New Text"


    Rectangle{
    id: button
    width: rootRect.width/6
    height: rootRect.height/8
    color: "black"
    x: 200; y: 200
    radius: 10

    }

    MouseArea{
        id: buttonClickArea
        width: 0
        anchors.rightMargin: 0
        anchors.bottomMargin: 0
        anchors.fill: button

        onClicked: {

                display.text = defaultText
        }
    }

}

Thank you for taking the time to read this and/or any replies.

Answer

Maz T picture Maz T · Jan 5, 2015

Using Qt 5.4.0 and Qt Creator 3.3.0, create New Project:

  1. Click New Project
  2. Qt Quick Application
  3. Click Choose...
  4. Name the project and select where to place it
  5. Click Next
  6. Select Qt Quick 2.4 from the drop-down menu
  7. Click Next
  8. Select desired Kit(s)
  9. Click Next
  10. Click Finish

Now You should see open main.qml file with following code:

import QtQuick 2.4
import QtQuick.Window 2.2

Window {
    visible: true
    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            Qt.quit();
        }

    }
}

Change it to:

import QtQuick 2.4
import QtQuick.Window 2.2

//### New Code ###

import QtQuick.Controls 1.3

//################

Window {
    id: window1
    visible: true

    //### New Code ###

    width: 400
    height: 500

    TextArea {
        id: textArea
        readOnly: true
        anchors.bottom: textInput.top
        anchors.bottomMargin: 6
        anchors.right: parent.right
        anchors.rightMargin: 8
        anchors.left: parent.left
        anchors.leftMargin: 7
        anchors.top: parent.top
        anchors.topMargin: 7
    }

    TextField {
        id: textInput
        y: 470
        height: 23
        anchors.right: sendButton.left
        anchors.rightMargin: 6
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 7
        anchors.left: parent.left
        anchors.leftMargin: 7
    }

    Button {
        id: sendButton
        x: 328
        y: 470
        width: 64
        height: 23
        text: qsTr("Send")
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 7
        anchors.right: parent.right
        anchors.rightMargin: 8

        onClicked: {
            CppClass.sendMessage(textInput.text, textArea);
            textInput.text = "";
        }
    }

    //################
}

Add C++ Class to Your project:

  1. Right Mouse Click project name in Projects viewer
  2. Click Add New...
  3. Select C++ Class if not already selected
  4. Click Choose...
  5. In Class name filed enter "CppClass"
  6. Set Base class to QObject
  7. Click Next
  8. Click Finish

Open cppclass.h and change it to:

#ifndef CPPCLASS_H
#define CPPCLASS_H

#include <QObject>

//### New Code ###

#include <QQuickItem>
#include <QQuickTextDocument>
#include <QTextDocument>

//################

class CppClass : public QObject
{
    Q_OBJECT
public:
    explicit CppClass(QObject *parent = 0);
    ~CppClass();

    //### New Code ###

    Q_INVOKABLE void sendMessage(const QString &msg, QQuickItem *textArea);

    //################

signals:

public slots:
};

#endif // CPPCLASS_H

Open cppclass.cpp and change it to:

#include "cppclass.h"

CppClass::CppClass(QObject *parent) : QObject(parent)
{

}

CppClass::~CppClass()
{

}
//### New Code ###

void CppClass::sendMessage(const QString &msg, QQuickItem *textArea)
{
    QTextDocument *textDocument = textArea->property("textDocument").value<QQuickTextDocument*>()->textDocument();

    textDocument->setHtml(textDocument->toHtml() + "\n<b>Text sent to Cpp side:</b> <i>" + msg + "</i>");
}

//################

Open main.cpp and change it to:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

//### New Code ###

#include <QQmlContext>

#include "cppclass.h"

//################

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    //### New Code ###

    CppClass cppClass;

    engine.rootContext()->setContextProperty("CppClass", &cppClass);

    //################

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

Run Your application, type some text to Input Field and click send.



In response to Dynamic Remo comment here's another way to have QML and C++ communicate. This approach is based on C++ emitting a signal and QML acting upon it. Following is the code to get it working.


cppclass.h

#ifndef CPPCLASS_H
#define CPPCLASS_H

#include <QObject>

#include <QDateTime>

class CppClass : public QObject
{
    Q_OBJECT
public:
    explicit CppClass(QObject *parent = 0);
    ~CppClass();

    Q_INVOKABLE void getCurrentTime();

signals:
    void timeUpdate(QString currentTime);

public slots:
};

#endif // CPPCLASS_H

cppclass.cpp

#include "cppclass.h"

CppClass::CppClass(QObject *parent) : QObject(parent)
{

}

CppClass::~CppClass()
{

}

void CppClass::getCurrentTime()
{
    emit timeUpdate(QDateTime::currentDateTime().toString("ddd dd MMMM yyyy hh:mm:ss.zzz"));
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QQmlContext>

#include "cppclass.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    CppClass cppClass;

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("CppClass", &cppClass);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml:

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

Window {
    id: rootWindow
    width: 400
    height: 400
    visible: true

    Connections {
        target: CppClass

        onTimeUpdate: {
            initailizeDllMsg.text = currentTime
        }
    }

    Text {
        id: initailizeDllMsg
        text: qsTr("{current time placeholder}")
        font.pointSize: 14
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
    }

    Button {
        id: button1
        x: 163
        y: 357
        text: qsTr("Show current time")
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 20
        anchors.horizontalCenter: parent.horizontalCenter

        onClicked: CppClass.getCurrentTime()
    }
}