Overlay Example Filter Tutorial

This guide covers creating a simple ADTF filter that displays random data in an overlay widget. After reading this guide, you will know how to:

How to create a simple overlay widget filter?

First, create a new filter project for the overlay widget filter using CMake.


cmake_minimum_required(VERSION 3.10.0)

set(EXAMPLE_NAME overlay_example)
set(PLUGIN_BINARY_OUTPUT_DIR "bin")

find_package(qt3ddisplay REQUIRED COMPONENTS base qmlbase)
find_package(Qt5 COMPONENTS Core OpenGL Quick Qml QuickWidgets 3DCore 3DExtras 3DRender 3DInput)

project(${EXAMPLE_NAME} VERSION 1.0.0)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

# Adds the project to the Visual Studio solution, which when build
# creates a shared object called overlay_example.adtfplugin
adtf_add_filter(${EXAMPLE_NAME}
                ${EXAMPLE_NAME}_filter.cpp
                ${EXAMPLE_NAME}_filter.h
                qml/${EXAMPLE_NAME}_filter_resources.qrc
                qml/${EXAMPLE_NAME}_filter_main.qml
                )

set_target_properties(${EXAMPLE_NAME} PROPERTIES 
                AUTORCC true 
                AUTOUIC true)

target_link_libraries(${EXAMPLE_NAME} PRIVATE
                adtf::qt3d::base)

# Adds the INSTALL project to the Visual Studio solution, which when build
# copies our filter to the subdirectory given as the second argument into ${PLUGIN_BINARY_OUTPUT_DIR}
adtf_install_filter(${EXAMPLE_NAME} ${PLUGIN_BINARY_OUTPUT_DIR})

set_target_properties(${EXAMPLE_NAME} PROPERTIES FOLDER examples/guides)

# Generates a plugindescription for our filter
adtf_create_plugindescription(
    TARGET
        ${EXAMPLE_NAME}
    PLUGIN_SUBDIR
        ${PLUGIN_BINARY_OUTPUT_DIR}
)

    

Now use the CMake-GUI to fill in all the information required by CMake to create the Visual Studio solution. Then open theoverlay_exampleproject in the solution explorer.

The header file of the filter

Just like before we continue by creating our overlay_example_filter.h header file.

            
#pragma once

#include <qt3ddisplay/base/qt3d_base_filter.h>

 // To implement a Filter which can be used in 3D-Display we subclass adtf::qt3d::cQt3DBaseFilter.
class cQt3DOverlay : public adtf::qt3d::cQt3DBaseFilter
{

public:
    // This macros provides some meta information about our Implementation.
    // This will be exposed by the plugin class factory.
    ADTF_CLASS_ID_NAME(cQt3DOverlay,
        "overlay.qt3d.cid",
        "Qt3D Overlay");

    // Constructor
    cQt3DOverlay();

    // Destructor
    ~cQt3DOverlay() = default;

};


            
          

The source file of the filter

Now we need to write the overlay_example_filter.cpp source file.

            
#include "overlay_example_filter.h"

// For simplicity use the necessary namespaces.
using namespace adtf::ucom;
using namespace adtf::streaming;
using namespace adtf::services;
using namespace adtf::base;
using namespace adtf::mediadescription;
using namespace adtf::qt3d;

// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cQt3DOverlay class will be available through the plugins class factory.
ADTF_PLUGIN("Qt3D Overlay", cQt3DOverlay)

// The main QML file gets loaded from the base class.
cQt3DOverlay::cQt3DOverlay():
    cQt3DBaseFilter(":/modules/Qt3DOverlay/overlay_example_filter_main.qml", false)
{
    // sets a short description for the component
    adtf::streaming::set_description(*this, "The overlay example filter creates an overlay widget within a specified overlay container.");

    // set help link to jump to documentation from ADTF Configuration Editor
    adtf::streaming::set_help_link(*this, "../doc/guides/tutorial_overlay_example.html");
}

            
          

The QML file of the filter

Now we need to write the overlay_example_filter_main.qml qml file.

            
// Import the Qt libaries.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQml 2.12

// Import the Adtf and Qt3DBase library.
import Adtf 1.0
import AdtfQt3DBase 1.0


Item
{
    id: root

    // Use readonly properties for constant definitions.
    readonly property int internalMargin: 10

    // Use the onCompleted handler to create an interface client.
    Component.onCompleted:
    {
        const qtshared = filter.createInterfaceClient("qtshared", "qtshared")

        // Get a reference of the 'overlayContainerLeft' and add the overlay widget.
        filter.connected.connect(function()
        {
            if (qtshared.connected)
            {
                const container = qtshared.getObject("overlayContainerLeft")
                container.addWidget(exampleOverlay)
            }
        })
    }

    // Use the Qt3DWidget to develop your own overlay.
    // The full range of Qt functionality can be used within this container.
    Qt3DWidget {
        id: exampleOverlay
        width: 350
        height: 150
        title: "Overlay Example"

        Rectangle {
            color: "transparent"
            anchors.fill: parent
            anchors.margins: internalMargin

            Text {
                id: vehicleStateInfo
                text: "Vehicle State"
                font.pixelSize: 12
                font.bold: true
                anchors.left: parent.left
                anchors.right: parent.right
            }

            GridLayout {
                columns: 2
                rowSpacing: internalMargin
                anchors.top: vehicleStateInfo.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.topMargin: internalMargin * 2

                Text {
                    id: batteryLevel
                    text: "Battery Level"
                    font.pixelSize: 12
                    horizontalAlignment: Text.AlignLeft
                }

                ProgressBar {
                    id: batteryLevelState
                    value: 0
                    from: 0
                    to: 100
                    Layout.alignment: Qt.AlignHCenter

                    background: Rectangle {
                        radius: 3
                        border.color: "#D3D3D3"
                    }

                    contentItem: Item {
                        implicitWidth: 150
                        implicitHeight: 20

                        Rectangle {
                            width: batteryLevelState.visualPosition * parent.width
                            height: parent.height
                            radius: 2
                            color: "#017BDD"
                        }
                    }

                    Text {
                        text: ("loading")
                        z: 1
                        anchors.fill: parent
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }

                    PropertyAnimation {
                        target: batteryLevelState
                        property: "value"
                        from: 0
                        to: 100
                        duration: 10000
                        running: true
                        loops: Animation.Infinite
                    }
                }

                Text {
                    id: vehicleTests
                    text: "Vehicle Tests"
                    font.pixelSize: 12
                    horizontalAlignment: Text.AlignLeft
                }

                Text {
                    id: vehicleTestResults
                    text: Math.floor(Math.random() * Math.floor(2)) === 1 ? "OK" : "Failed"
                    font.pixelSize: 12
                    color: text === "OK" ? "green" : "red"

                    horizontalAlignment: Text.AlignHCenter
                    Layout.alignment: Qt.AlignHCenter
                }

                Text {
                    id: oilFillingLevel
                    text: "Oil Filling Level"
                    font.pixelSize: 12
                    horizontalAlignment: Text.AlignLeft
                }

                ProgressBar {
                    id: oilFillingLevelState
                    from: 0
                    to: 100
                    value: ((Math.random() * (100 - 90) + 90 ) | 0)
                    Layout.alignment: Qt.AlignHCenter

                    background: Rectangle {
                        radius: 3
                        border.color: "#D3D3D3"
                    }

                    contentItem: Item {
                        implicitWidth: 150
                        implicitHeight: 20

                        Rectangle {
                            width: oilFillingLevelState.visualPosition * parent.width
                            height: parent.height
                            radius: 2
                            color: "#017BDD"
                        }
                    }

                    Text {
                        text: (oilFillingLevelState.value + " %")
                        z: 1
                        anchors.fill: parent
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }
                }
            }
        }
    }

}



            
          

The resources file of the filter

Now we need to write the overlay_example_filter_resources.qrc resources file. For detailed information about the Qt Resource System have a look at Qt Resources System.

            
<RCC>
    <qresource prefix="/modules/Qt3DOverlay">
        <file>overlay_example_filter_main.qml</file>
    </qresource>
</RCC>

            
          

Finally we need to build the Project.

Now we want to integrate and test our filters in an ADTF Project. We can accomplish this using the Configuration Editor see Getting Started page.

Where to go next?

Have a look at the Cube Example Filter.