QML concpets

Loading QML Components from C++


Calling Functions

QML functions can be called from C++ and vice-versa.

All QML functions are exposed to the meta-object system and can be called using QMetaObject::invokeMethod(). Here is a C++ application that uses this to call a QML function:

// MyItem.qml
import QtQuick 1.0

Item {
    function myQmlFunction(msg) {
        console.log("Got message:", msg)
        return "some return value"
    }
}
// main.cpp
QDeclarativeEngine engine;
QDeclarativeComponent component(&engine, "MyItem.qml");
QObject *object = component.create();

QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
        Q_RETURN_ARG(QVariant, returnedValue),
        Q_ARG(QVariant, msg));

qDebug() << "QML function returned:" << returnedValue.toString();
delete object;

Notice the Q_RETURN_ARG() and Q_ARG() arguments for QMetaObject::invokeMethod() must be specified as QVariant types, as this is the generic data type used for QML functions and return values.

To call a C++ function from QML, the function must be either a Qt slot, or a function marked with the Q_INVOKABLE macro, to be available to QML. In the following example, the QML code invokes methods on the myObject object, which has been set using QDeclarativeContext::setContextProperty():

// MyItem.qml
import QtQuick 1.0

Item {
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            myObject.cppMethod("Hello from QML")
            myObject.cppSlot(12345)
        }
    }
}
class MyClass : public QObject
{
    Q_OBJECT
public:
    Q_INVOKABLE void cppMethod(const QString &msg) {
        qDebug() << "Called the C++ method with" << msg;
    }

public slots:
    void cppSlot(int number) {
        qDebug() << "Called the C++ slot with" << number;
    }
};

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

    QDeclarativeView view;
    MyClass myClass;
    view.rootContext()->setContextProperty("myObject", &myClass);

    view.setSource(QUrl::fromLocalFile("MyItem.qml"));
    view.show();

    return app.exec();
}

Managing resource files with the Qt resource system

The Qt resource system allows resource files to be stored as binary files in an application executable. This can be useful when building a mixed QML/C++ application as it enables QML files (as well as other resources such as images and sound files) to be referred to through the resource system URI scheme rather than relative or absolute paths to filesystem resources. Note, however, that if you use the resource system, the application executable must be re-compiled whenever a QML source file is changed in order to update the resources in the package.

To use the resource system in a mixed QML/C++ application:

  • Create a .qrc resource collection file that lists resource files in XML format
  • From C++, load the main QML file as a resource using the :/ prefix or as a URL with the qrc scheme

Once this is done, all files specified by relative paths in QML will be loaded from the resource system instead. Use of the resource system is completely transparent to the QML layer; this means all QML code should refer to resource files using relative paths and should not use the qrc scheme. This scheme should only be used from C++ code for referring to resource files.

Here is a application packaged using the Qt resource system. The directory structure looks like this:

project
    |- example.qrc
    |- main.qml
    |- images
        |- background.png
    |- main.cpp
    |- project.pro

The main.qml and background.png files will be packaged as resource files. This is done in the example.qrc resource collection file:

<!DOCTYPE RCC>
<RCC version="1.0">

<qresource prefix="/">
    <file>main.qml</file>
    <file>images/background.png</file>
</qresource>

</RCC>

Since background.png is a resource file, main.qml can refer to it using the relative path specified in example.qrc:

// main.qml
import QtQuick 1.0

Image { source: "images/background.png" }

To allow QML to locate resource files correctly, the main.cpp loads the main QML file, main.qml, as a resource file using the qrc scheme:

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

    QDeclarativeView view;
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

    return app.exec();
}

Finally project.pro uses the RESOURCES variable to indicate that example.qrc should be used to build the application resources:

QT += declarative

SOURCES += main.cpp
RESOURCES += example.qrc



What is Qt meta -object?

The Meta-Object System

Qt's meta-object system provides the signals and slots mechanism for inter-object communication, run-time type information, and the dynamic property system.

The meta-object system is based on three things:

  1. The QObject class provides a base class for objects that can take advantage of the meta-object system.
  2. The Q_OBJECT macro inside the private section of the class declaration is used to enable meta-object features, such as dynamic properties, signals, and slots.
  3. The Meta-Object Compiler (moc) supplies each QObject subclass with the necessary code to implement meta-object features.

The moc tool reads a C++ source file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces another C++ source file which contains the meta-object code for each of those classes. This generated source file is either #include'd into the class's source file or, more usually, compiled and linked with the class's implementation.

In addition to providing the signals and slots mechanism for communication between objects (the main reason for introducing the system), the meta-object code provides the following additional features:

It is also possible to perform dynamic casts using qobject_cast() on QObject classes. The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries. It attempts to cast its argument to the pointer type specified in angle-brackets, returning a non-zero pointer if the object is of the correct type (determined at run-time), or 0 if the object's type is incompatible.

For example, let's assume MyWidget inherits from QWidget and is declared with the Q_OBJECT macro:

    QObject *obj = new MyWidget;

The obj variable, of type QObject *, actually refers to a MyWidget object, so we can cast it appropriately:

    QWidget *widget = qobject_cast<QWidget *>(obj);

The cast from QObject to QWidget is successful, because the object is actually a MyWidget, which is a subclass of QWidget. Since we know that obj is a MyWidget, we can also cast it to MyWidget *:

    MyWidget *myWidget = qobject_cast<MyWidget *>(obj);

The cast to MyWidget is successful because qobject_cast() makes no distinction between built-in Qt types and custom types.

    QLabel *label = qobject_cast<QLabel *>(obj);
    // label is 0

The cast to QLabel, on the other hand, fails. The pointer is then set to 0. This makes it possible to handle objects of different types differently at run-time, based on the type:

    if (QLabel *label = qobject_cast<QLabel *>(obj)) {
        label->setText(tr("Ping"));
    } else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {
        button->setText(tr("Pong!"));
    }

While it is possible to use QObject as a base class without the Q_OBJECT macro and without meta-object code, neither signals and slots nor the other features described here will be available if the Q_OBJECT macro is not used. From the meta-object system's point of view, a QObject subclass without meta code is equivalent to its closest ancestor with meta-object code. This means for example, that QMetaObject::className() will not return the actual name of your class, but the class name of this ancestor.

Therefore, we strongly recommend that all subclasses of QObject use the Q_OBJECT macro regardless of whether or not they actually use signals, slots, and properties. 

What is moc ?


Using the Meta-Object Compiler (moc)

The Meta-Object Compiler, moc, is the program that handles Qt's C++ extensions.

The moc tool reads a C++ header file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces a C++ source file containing the meta-object code for those classes. Among other things, meta-object code is required for the signals and slots mechanism, the run-time type information, and the dynamic property system.

The C++ source file generated by moc must be compiled and linked with the implementation of the class.

If you use qmake to create your makefiles, build rules will be included that call the moc when required, so you will not need to use the moc directly. For more background information on moc, see Why Doesn't Qt Use Templates for Signals and Slots?

Usage

moc is typically used with an input file containing class declarations like this:

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = 0);
    ~MyClass();

signals:
    void mySignal();

public slots:
    void mySlot();
};

In addition to the signals and slots shown above, moc also implements object properties as in the next example. The Q_PROPERTY() macro declares an object property, while Q_ENUMS() declares a list of enumeration types within the class to be usable inside the property system.

In the following example, we declare a property of the enumeration type Priority that is also called priority and has a get function priority() and a set function setPriority().

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority)
    Q_ENUMS(Priority)

public:
    enum Priority { High, Low, VeryHigh, VeryLow };

    MyClass(QObject *parent = 0);
    ~MyClass();

    void setPriority(Priority priority) { m_priority = priority; }
    Priority priority() const { return m_priority; }

private:
    Priority m_priority;
};

The Q_FLAGS() macro declares enums that are to be used as flags, i.e. OR'd together. Another macro, Q_CLASSINFO(), allows you to attach additional name/value pairs to the class's meta-object:

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author", "Oscar Peterson")
    Q_CLASSINFO("Status", "Active")

public:
    MyClass(QObject *parent = 0);
    ~MyClass();
};

The output produced by moc must be compiled and linked, just like the other C++ code in your program; otherwise, the build will fail in the final link phase. If you use qmake, this is done automatically. Whenever qmake is run, it parses the project's header files and generates make rules to invoke moc for those files that contain a Q_OBJECT macro.

If the class declaration is found in the file myclass.h, the moc output should be put in a file called moc_myclass.cpp. This file should then be compiled as usual, resulting in an object file, e.g., moc_myclass.obj on Windows. This object should then be included in the list of object files that are linked together in the final building phase of the program.

Writing Make Rules for Invoking moc

For anything but the simplest test programs, it is recommended that you automate running the moc. By adding some rules to your program's makefile, make can take care of running moc when necessary and handling the moc output.

We recommend using the qmake makefile generation tool for building your makefiles. This tool generates a makefile that does all the necessary moc handling.

If you want to create your makefiles yourself, here are some tips on how to include moc handling.

For Q_OBJECT class declarations in header files, here is a useful makefile rule if you only use GNU make:

moc_%.cpp: %.h
        moc $(DEFINES) $(INCPATH) $< -o $@

If you want to write portably, you can use individual rules of the following form:

moc_foo.cpp: foo.h
        moc $(DEFINES) $(INCPATH) $< -o $@

You must also remember to add moc_foo.cpp to your SOURCES (substitute your favorite name) variable and moc_foo.o or moc_foo.obj to your OBJECTS variable.

Both examples assume that $(DEFINES) and $(INCPATH) expand to the define and include path options that are passed to the C++ compiler. These are required by moc to preprocess the source files.

While we prefer to name our C++ source files .cpp, you can use any other extension, such as .C.cc.CC.cxx, and .c++, if you prefer.

For Q_OBJECT class declarations in implementation (.cpp) files, we suggest a makefile rule like this:

foo.o: foo.moc

foo.moc: foo.cpp
        moc $(DEFINES) $(INCPATH) -i $< -o $@

This guarantees that make will run the moc before it compiles foo.cpp. You can then put

#include "foo.moc"

at the end of foo.cpp, where all the classes declared in that file are fully known.

Command-Line Options

Here are the command-line options supported by the moc:

OptionDescription
-o<file>Write output to <file> rather than to standard output.
-f[<file>]Force the generation of an #include statement in the output. This is the default for header files whose extension starts with H or h. This option is useful if you have header files that do not follow the standard naming conventions. The <file> part is optional.
-iDo not generate an #include statement in the output. This may be used to run the moc on on a C++ file containing one or more class declarations. You should then #include the meta-object code in the .cpp file.
-nwDo not generate any warnings. (Not recommended.)
-p<path>Makes the moc prepend <path>/ to the file name in the generated #include statement.
-I<dir>Add dir to the include path for header files.
-EPreprocess only; do not generate meta-object code.
-D<macro>[=<def>]Define macro, with optional definition.
-U<macro>Undefine macro.
@<file>Read additional command-line options from <file>. Each line of the file is treated as a single option. Empty lines are ignored. Note that this option is not supported within the options file itself (i.e. an options file can't "include" another file).
-hDisplay the usage and the list of options.
-vDisplay moc's version number.
-FdirMac OS X. Add the framework directory dir to the head of the list of directories to be searched for header files. These directories are interleaved with those specified by -I options and are scanned in a left-to-right order (see the manpage for gcc). Normally, use -F /Library/Frameworks/

You can explicitly tell the moc not to parse parts of a header file. moc defines the preprocessor symbol Q_MOC_RUN. Any code surrounded by

#ifndef Q_MOC_RUN
    ...
#endif

is skipped by the moc.

Diagnostics

moc will warn you about a number of dangerous or illegal constructs in the Q_OBJECT class declarations.

If you get linkage errors in the final building phase of your program, saying that YourClass::className() is undefined or that YourClass lacks a vtable, something has been done wrong. Most often, you have forgotten to compile or #include the moc-generated C++ code, or (in the former case) include that object file in the link command. If you use qmake, try rerunning it to update your makefile. This should do the trick.

Limitations

moc does not handle all of C++. The main problem is that class templates cannot have signals or slots. Here is an example:

class SomeTemplate<int> : public QFrame
{
    Q_OBJECT
    ...

signals:
    void mySignal(int);
};

Another limitation is that moc does not expand macros, so you for example cannot use a macro to declare a signal/slot or use one to define a base class for a QObject.

Less importantly, the following constructs are illegal. All of them have alternatives which we think are usually better, so removing these limitations is not a high priority for us.

Multiple Inheritance Requires QObject to Be First

If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject. Also, be sure that only the first inherited class is a QObject.

// correct
class SomeClass : public QObject, public OtherClass
{
    ...
};

Virtual inheritance with QObject is not supported.

Function Pointers Cannot Be Signal or Slot Parameters

In most cases where you would consider using function pointers as signal or slot parameters, we think inheritance is a better alternative. Here is an example of illegal syntax:

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(void (*apply)(List *, void *), char *); // WRONG
};

You can work around this restriction like this:

typedef void (*ApplyFunction)(List *, void *);

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(ApplyFunction, char *);
};

It may sometimes be even better to replace the function pointer with inheritance and virtual functions.

Enums and Typedefs Must Be Fully Qualified for Signal and Slot Parameters

When checking the signatures of its arguments, QObject::connect() compares the data types literally. Thus, Alignment and Qt::Alignment are treated as two distinct types. To work around this limitation, make sure to fully qualify the data types when declaring signals and slots, and when establishing connections. For example:

class MyClass : public QObject
{
    Q_OBJECT

    enum Error {
        ConnectionRefused,
        RemoteHostClosed,
        UnknownError
    };

signals:
    void stateChanged(MyClass::Error error);
};

Type Macros Cannot Be Used for Signal and Slot Parameters

Since moc doesn't expand #defines, type macros that take an argument will not work in signals and slots. Here is an illegal example:

#ifdef ultrix
#define SIGNEDNESS(a) unsigned a
#else
#define SIGNEDNESS(a) a
#endif

class Whatever : public QObject
{
    Q_OBJECT

signals:
    void someSignal(SIGNEDNESS(int));
};

A macro without parameters will work.

Nested Classes Cannot Have Signals or Slots

Here's an example of the offending construct:

class A
{
public:
    class B
    {
        Q_OBJECT

    public slots:   // WRONG
        void b();
    };
};

Signal/Slot return types cannot be references

Signals and slots can have return types, but signals or slots returning references will be treated as returning void.

Only Signals and Slots May Appear in the signals and slots Sections of a Class

moc will complain if you try to put other constructs in the signals or slots sections of a class than signals and slots.

What are QML FAQ in interviews?

Q) What is Qml ?
QML is the name of the language (just like C++, which is another language...)
QML stands for Qt Meta Language or Qt Modelling Language is a user interface markup language.
Q) How to call c++ call from QML?
QML call C + + methods with the Qt meta-object system. Like below:
onClicked: parent.color = parent.randomColor ()

Q) What are Four ways of integreting C++ with Qml?
Subclassing QQuickItem: QQuickItem allows you to write your own visual and non-visual QML items using C++.
Registering C++ types with QML: C++ classes can be registered with the QML type system, allowing them to be instantiated as QML types.
Registering Context Properties: QObjects can be registered with the QML context, allowing their properties to be directly accessed.
Accessing QML objects through the QML object tree: All QML objects reside in a tree hierarchy and can be accessed via the root of the tree.
http://www.ics.com/blog/multilayered-architecture-qt-quick

Q) How to call a C++ function from a qml?
Through setcontext property.
Note
Loading a main.qml with a simple Item as the root type through the QmlApplicationEngine will not show anything on your display, as it requires a window to manage a surface for rendering. The engine is capable of loading qml code which does not contain any user interface (e.g plain objects). Because of this it does not create a window for you by default.
The qmlscene or the new qml runtime will internally first check if the main qml file contains a window as a root item and if not create one for you and set the root item as a child to the newly created window.

Q)What is Q_INVOKABLE?
Add callable methods using Q_INVOKABLE or Qt slots, and connect to Qt signals with an onSignal syntax

Q)How to call a QML function from c++?
QML functions can be called from C++ and vice-versa.
All QML functions are exposed to the meta-object system and can be called usingQMetaObject::invokeMethod(). Here is a C++ application that uses this to call a QML function:
// MyItem.qml
import QtQuick 1.0
Item {
    function myQmlFunction(msg) {
        console.log("Got message:", msg)
        return "some return value"
    }
}
// main.cpp
QDeclarativeEngine engine;
QDeclarativeComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
        Q_RETURN_ARG(QVariant, returnedValue),
        Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;

Q)How to call a C++ function from QML ?
A C++ function can be called from a qml using set contextpropery in c++.
http://doc.qt.io/qt-4.8/qtbinding.html
All QML signals are automatically available to C++, and can be connected to using QObject::connect() like any ordinary Qt C++ signal.
The signal is sent to QML, and the slot is invoked from QML.
There are different ways to send signals from C++ to QML and back. In this article, we show how to do this by embedding a C++ class directly into QML. This has the advantage that no Qt::connect connections need to be set-up manually.
In our example, we have a Receiver class that is implemented in C++.
This class defines a signal sendToQml and a slot receiveFromQml.
 Both have an integer parameter.
The signal is sent to QML, and the slot is invoked from QML.
Example:
//signal_slot.pro
TEMPLATE = app
QT += qml quick
#export QT_SELECT=5
SOURCES += main.cpp \
    receiver.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 += \
    receiver.h
//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "receiver.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    Receiver receiver;
    QQmlContext* ctx = engine.rootContext();
    ctx->setContextProperty("receiver", &receiver);
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
    receiver.sendToQml(43);
    //QDeclarativeView view;
    //view.rootContext()->setContextProperty("_EBSCModel",m_EBSCDtcDataModel);
    //sourcePath = "qrc:///DTC/qml/ITSDTC.qml";
    //view.setSource(QUrl(sourcePath));
    return app.exec();
}
//receiver.h
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject
{
    Q_OBJECT
public:
    explicit Receiver(QObject *parent = 0);
signals:
    void sendToQml(int count);
public slots:
    void receiveFromQml(int count);
};
#endif // RECEIVER_H
//receiver.cpp
#include "receiver.h"
#include <QDebug>
Receiver::Receiver(QObject *parent) :
   QObject(parent)
{
}

void Receiver::receiveFromQml(int count) {
    qDebug() << "Received in C++ from QML:" << count;
}
//main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
Window {
    id: test
    visible: true
    width: 200
    height: 50
    Connections {
        target: receiver
        onSendToQml: {
            console.log("Received in QML from C++: " + count)
        }
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            receiver.receiveFromQml(42);
        }
    }

    Text {
        text: qsTr("Press me to send a signal to C++")
        anchors.centerIn: parent
    }
}















Comments

Popular posts from this blog

Dependency Injection in C++

Device Driver Development