<< to CrossControl homepage

Support & Service Center

Qt Programming

We recommend to refer also to the following web-pages for Qt-related questions and problems:

 

Using QML inside a QtWidgets project

Brief

QtWidgets and QML does not use the same graphical backend and can not normally be combined. However, there are workarounds for situations where it is a requirement. One such workaround is described in this document. The QQuickWidget.

The QQuickWidget

General

Normally QML is run on a scenegraph that is in control of the OpenGL pipeline that owns the frame buffer. Typically initialized by a QQuickView or similar “root” class for QML. This is why it doesn’t combine natively with QWidgets that use their own, different, framebuffer connection. There is one QWidget that gets around this limitation, albeit with a performance hit – the QQuickWidget. It does the same QML initialization as a QQuickView with the exception that instead of giving QML control of the framebuffer, QML is given an OpenGL Framebuffer Object (FBO for short) as render target. This FBO is then used by the QQuickWidget to draw itself first (more on that later) in the normal widget pipeline.  

Limitations

  • The use of an FBO causes a performance hit since the texels (“pixels” not yet on the framebuffer) must be effectively copied an extra time.
  • In the case of iMX5 platforms, use of a FBO may be a showstopper. There is a bug that potentially (yet to be fully investigated) crashes the GPU when non-tiny FBOs or PBOs are used.
  • Threaded render loops are not allowed. This limits the performance benefits of certain components, such as Animator classes and vsync driven animations.
  • Due to how QQuickWidgets have to draw themselves before other widgets, its QML content can not use transparency to reveal widgets below, so partially “see-through” QML components are not possible.
    Note: Widgets can still go on top of the QML content as normal.
  • The point above can be worked around by designating the QQuickWidget as always-stack-on-top (attribute Qt::AlwaysStackOnTop). This however, merely reverses the limitation since stacking order is broken and no other widgets can go above the QML instead.
Note: Since it is the QML buffer itself that needs to be transparent we need to enable alpha for it. This is done by setting the attribute Qt::WA_TranslucentBackground on the top-level QML Window, request an alpha channel, and change the QML scenegraph’s clear color to Qt::transparent (setClearColor(Qt::transparent));

Usage

Essentially, QQuickWidgets are added just like any other widgets. There are a few things to keep in mind though.
  1. They reside in their own QT module that needs to be included in the .pro
    QT += quickwidgets
  2. If added in a form or through the designer, do not set the source property directly if any rootContexts need to be available during QML initialization.
    QML content will be initialized when the source is set and by default this is done when the QQuickWidget itself is created.
  3. In the constructor that adds the QQuickWidget – i.e. the widget that has it in its UI file or manually adds it:
  4. (If rootContext access is needed) Include
  5. Register any custom QML classes before or after the QQuickWidget is initialized but before any QML source is loaded.
  6. After the QQuickWidget has been created but before its source is set, register any rootContext properties or objects in its QML view.
  7. Only after this is all done, set its source to your root QML file to initialize the QML content itself.
  8. Finally, with all components initialized, create any signal/slot connections as needed between the QML content and the rest of your widget application

Example code

#include "ui_application.h"
#include <QQmlContext>
 
Application::Application(QWidget *parent)
    : QWidget(parent), ui(new Ui::Application) {
 
  // QML engine is spun up by the quickwidget's constructor, i.e. during setupUi.
  qmlRegisterType<FPSText>("CrossControl", 1, 0, "FPSText");
  qmlRegisterType<CircularMeterGL>("CrossControl", 1, 0, "CircularMeter");
  ui->setupUi(this);
 
  // RootContexts must be added after setupUI, but before qml source is set.
  // So if the quickwidget is in a form, the source property must not be set
  // there. It must only be set after we've had the chance to register
  // rootProperties in the engine, which we can only do after the form has been
  // processed and there is a qml engine to access.
  ui->quickWidget->rootContext()->setContextProperty("externalSlider",
                                                     ui->horizontalSlider);
  ui->quickWidget->rootContext()->setContextProperty("externalCheckbox",
          <                                           ui->checkBox);
 
  // Now we can set the source
  ui->quickWidget->setSource(QUrl("qrc:/main.qml"));
 
  // QML is fully initialized. We can now set up connections to it
  connect(ui->pushButtonClose, &QPushButton::click, this, &QApplication::quit);
}
Category: 

OPC-UA in Qt 5.12


QT Open62541plugin is available under open source license starting from QT 5.13.1.
Our newest non engineering release at the moment is 5.12 and we don’t have the commercial automation package
available in this version. But OPC Open62541 QT plugin has been added in QT 5.12 as a "technology preview".
Though, the plugin is not built by default, it can be built into the Qt 5.12 release.
Follow the instructions below to build the plugin (VI2 used in this example).

In LinX VM 4.0.3, clone the git repo:
ccs@LinX-VM:~/git$ git clone http://code.qt.io/qt/qtopcua.git
Cloning into 'qtopcua'...
warning: redirecting to https://code.qt.io/qt/qtopcua.git/
remote: Counting objects: 7848, done.
remote: Compressing objects: 100% (3881/3881), done.
remote: Total 7848 (delta 4887), reused 6344 (delta 3892)
Receiving objects: 100% (7848/7848), 2.39 MiB | 1.84 MiB/s, done.
Resolving deltas: 100% (4887/4887), done.

Then run qmake to configure the stuff for VS/VI2
ccs@LinX-VM:~/git/qtopcua$ /opt/VI2/sysroots/x86_64-linux/Qt-5.12.0/bin/qmake
Info: creating stash file /home/ccs/git/qtopcua/.qmake.stash
Info: creating cache file /home/ccs/git/qtopcua/.qmake.cache
 
Running configuration tests...
Checking for Open62541... no
Checking for Unified Automation C++ SDK... no
Done running configuration tests.
Configure summary:
Qt Opcua:
  Open62541 .............................. yes
  Unified Automation C++ SDK ............. no
  Support for namespace 0 NodeId names ... yes
  Namespace 0 NodeIds generator .......... no

Qt is now configured for building. Just run 'make'.
Once everything is built, you must run 'make install'.
Qt will be installed into '/opt/VI2/sysroots/cortexa9hf-neon-poky-linux-gnueabi/opt/Qt-5.12.0'.

It will not detect Open62541 or UA C++ SDK in the VS/VI2 image, which is correct since the libraries are not included in the image.
But the Qt module has 3rd-party library code for Open62541 and will compile this.

Now run "make" and "make install" to install to VS/VI2 SDK folder.
Then use qmake to build examples:
ccs@LinX-VM:~/git/qtopcua/examples/opcua$ /opt/VI2/sysroots/x86_64-linux/Qt-5.12.0/bin/qmake 
ccs@LinX-VM:~/git/qtopcua/examples/opcua$ make -j6 

This seems to work fine for the default Qt 5.12.0 included in the VM and Qt libraries we provide for VS/VI2.
To transfer the built libraries to the target (target IP = x.x.x.x), use the Linux command ‘rsync’:
$ rsync -av /opt/VI2/sysroots/cortexa9hf-neon-poky-linux-gnueabi/opt/Qt-5.12.0 ccs@x.x.x.x:/opt

Link to OPC-UA info on Qt Homepage

Environment and Versions: 
LinX SW Suite v4.0.3 iMX6 (VS/VI2)
Applies to version: 
Qt 5.12 (or higher)

Using Qt modal popups on CCpilot VS

The iMX6 display computers CCpilot VS and CCpilot VI2 uses a combination of Wayland, Weston and Qt that has a problem with modal popups, resulting in that a Qt application running in Weston cannot set a popup as modal.

It is possible to do a work-around to create a modal popup. A QtWidgets example is attached to this article to show three examples of modal popups on the VS.

Another approach can be to not use Weston and run a Qt application in EGLFS mode instead. A separate article describes how this can be done.

Environment and Versions: 
CCpilot VS 1.2 or higher
CCPilot VI2
Applies to version: 
Qt5

Full screen applications on Qt 5.9.4

A bug in QtWayland 5.9.4 affects how Qt sends fullscreen requests to Wayland. As a result of this bug, functions such as QMainWindow.showFullscreen() does not make the application full screen - only frameless. In order to bypass the bug, the application’s resolution should be fixed to that of the screen. For QWidget based applications, do the following:

QMainWindow view;
view.resize(1280, 800);
view.showFullscreen();
A similar approach can be used for QML applications.
Applies to version: 
CCP VS 1.2.0.0

Using keyboard input in a Qt application in CClinux 1.2.0.0 or newer

On devices running CClinux v1.2.0.0 or newer, Qt applications using keyboard input need to be invoked with the evdevkeyboard plugin flag enabled:

$ ./myApp -plugin evdevkeyboard
Note: In CClinux 1.4.1.0 this flag is enabled by default when running applications after device startup. If invoking an application during startup (e.g. from a script in rcX.c) the evdevkeyboard plugin still needs to be passed on to the application.
Applies to version: 
CCP VS 1.2.0.0

Change Qt Creator font

This article describes how to alter the font used by Qt Creator in LinX Software Suite 3.0.
While it is possible to change the font used by the text editor within Qt Creator, it is not possible to change font which is used for menus etc. through a setting; it has to be made outside of Qt Creator.

Follow these steps to change the font used by Qt Creator:

  1. Close Qt Creator
  2. Open the directory /opt/Qt-5.7.1/lib/fonts
  3. Create a backup directory on a suitable location (under fonts for example)
  4. Move all the fonts to the backup directory
  5. Place one font of your choosing in /opt/Qt-5.7.1/lib/fonts
  6. Start Qt Creator

The selected font will now be used by Qt Creator. It is also available to choose as a Text Editor font through the settings. Qt Creator will use a “Source Code Pro” as the default font if the font directory is empty.

Below are examples on the default font, DejuVuMono and an empty /opt/Qt-5.7.1/lib/fonts directory:

defaultfont.jpgnofont.pngdejavumono.png

Category: 
Applies to version: 
LinX Software Suite 3.0

Use new signal and slot syntax for cleaner code

Qt 5 introduced a new syntax for connecting signals with slot which is highly recommended to use. The old syntax is still valid but there are numerous reasons why the new syntax should be used:

  • Compile time check of the existence of the signals and slot, of the types, or if the Q_OBJECT is missing.
  • Argument can be by typedefs or with different namespace specifier, and it works.
  • Possibility to automatically cast the types if there is implicit conversion (e.g. from QString to QVariant)
  • It is possible to connect to any member function of QObject, not only slots.

Old syntax

connect(
    sender, SIGNAL( valueChanged( QString, QString ) ),
    receiver, SLOT( updateValue( QString ) )
);

New syntax

connect(
    sender, &Sender::valueChanged,
    receiver, &Receiver::updateValue
);

For further reading please follow and read this article: New Signal Slot Syntax

Category: 

How to avoid QTimer intervals being affected by graphical updates

This article will present one solution how to avoid QTimers instantiated in C++ (backend) to be affected by graphical changes in QML (frontend).

Whenever QObjects are instantiated in C++ they will be created and belong to the thread which they were created in. If no other threads are created during runtime, then there will only be the Main thread available. The QML code will always be executed in the Main thread; it is therefore recommended to not have CPU-intensive calculations performed in the Main thread since this may affect the graphical performance.

If the graphics require CPU-time due to changes of the layout (loading new content etc.) this will affect any QObjects running in the Main thread. If we would create a QTimer in the Main thread in C++ and assign it a short interval time and then load content in QML, then the interval could be heavily affected, leading to an uneven pace of timeout triggers from the QTimer.

If there is a need for an even pace which is not affected by changes in the GUI (or other QObjects) running in the Main thread, then here is one example on how achieve it.

Use separate threads

The created QTimers will need to run in their own separate threads to avoid being affected by other QObjects or the GUI running in the Main thread.

Any class which inherits from the QObject class may easily be moved to their own thread using the QThread class. To guarantee that QTimers are actually created in the new thread there a few options, but one of the easier ways are by connecting the signal started from QThread to an appropriate slot of the class which should hold the QTimer. Our example will consist of a class named CyclicWorker which has a slot called Initialize which will create the QTimer.

Note that this is not an complete example, you will need to apply the strategy based on your need.

A class which inherits from the QObject class:

class CyclicWorker : public QObject
{
    Q_OBJECT
    public:
 
    public slots:
    void Initialize();
 
    private:
    void pollInput():
    QTimer *m_timer;
}
 
/**
 * @brief Initialize the timer once the class have been moved to a separate thread. 
 */
void CyclicWorker::Initialize()
{
    m_timer = new QTimer(this);
    m_timer->setInterval(100);
    m_timer->setTimerType(Qt::PreciseTimer);
    connect(m_timer, &QTimer::timeout,this, &CyclicWorker::pollInput, Qt::DirectConnection);
}

Instanciate the class and move it to a separate thread using these steps:

QThread threadHandle;
CyclicWorker m_cyclicWorker;
 
QObject::connect(&threadHandle, &QThread::started, m_cyclicWorker, &CyclicWorker::Initialise);
m_cyclicWorker->moveToThread(&threadHandle);
threadHandle.start();

Once the thread has started it will trigger the Initialize slot in CyclicWorker which then will create the QTimer and assign in to the member variable m_timer. This timer will now execute in the new thread and not in the Main thread, leading to a stable interval betweeen each timeout.

Category: 

Qt - Compiling display specific code for Virtual Machine

As you progress in your code development you may find there are some specific pieces of code that will only compile when building for a display and not when building for the Virtual Machine (VM).  In the posted code example I use the PWM outputs of the VC/VA as an example although any display specific hardware is likely to have the same issue.  In these intances, because the VM doesnt have the display hardware available, your code will not compile and run on the VM if display specific hardware is referenced in your code.  Even though this hardware is not accessable to the VM, it is still often useful to run your code and perform some testing inside the VM on non hardware related items.  The posted example demonstrates how you can write your display-hardware specific code so it will work both for the displays and the VM without commenting or modification.  

 

Note: The code example will only work for ARM based displays.  The code example uses the processor type to determine if the code is being built for an ARM based display or the VM.  Because the VM and the XM units both use x86 based processors, the example will not work to determine if the code is being built for an XM unit or the VM.

 

 

AttachmentSize
Binary Data running_code_vm_arm.tar_.gz353.2 KB
Environment and Versions: 

ARM

Qt - Using Configurable IO on the VC / VA

The attached example shows how to use the configurable inputs on the VC and VA devices.  The code is well commented.  Further information about the functions available can be found in the CCAux documenation found on the display specific page of our support site.  Currently, both the VA and VC display use CCAux 2.8.3 which can be found here: 


http://support.crosscontrol.com/sites/default/files/documentation/Displays/CCpilot%20VA/Manuals/CCAux_2.8.3.0.pdf

This may be updated in future releases so please check the most up to date version of CCAux and make sure you are using the correct documenation.

Note: On both the VA and VC devices there was an issue in some OS releases which will prevent this and other functions specific to CCAux version 2.8.3 from working.  If you attempt to run this example and the inputs don't work (in which case the debug output should print an error in the application) please take the following steps to make sure this example, as well as other CCAux 2.8.3, will work.

  • Log into the display with the terminal
  • Navigate to the '/opt/lib' directory ('cd /opt/lib')
  • Type 'ls libcc-aux2.so*'
  • If there are files that are listed do the following:
    • Type 'rm libcc-aux2.so*' and press enter
    • Reboot the display

This issue should be resolved in future versions of the OS.

 

 

AttachmentSize
Binary Data io_example.tar_.gz491.02 KB
Environment and Versions: 

Qt4 Qt5 QML

Pages

whatever