Category Archives: Qt tips&tricks

Collection of Qt tips and tricks, which I have been deal with

How to vibrate with Qt/QML on Android?

Short answer – pretty simple. Thanks to QtAndroidExtras

First we need to add to your .pro file:

android: QT += androidextras

 

then add simple class to your codebase. Header:

#ifndef VIBRATOR_H
#define VIBRATOR_H

#include <QObject>

#if defined(Q_OS_ANDROID)
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#endif
class Vibrator : public QObject
{
    Q_OBJECT
public:
    explicit Vibrator(QObject *parent = 0);
signals:
public slots:
    void vibrate(int milliseconds);
private:
#if defined(Q_OS_ANDROID)
    QAndroidJniObject vibratorService;
#endif
};

#endif // VIBRATOR_H

 

and the code:

#include "vibrator.h"
#include <QDebug>

Vibrator::Vibrator(QObject *parent) : QObject(parent)
{
#if defined(Q_OS_ANDROID)
    QAndroidJniObject vibroString = QAndroidJniObject::fromString("vibrator");
    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
    QAndroidJniObject appctx = activity.callObjectMethod("getApplicationContext","()Landroid/content/Context;");
    vibratorService = appctx.callObjectMethod("getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;", vibroString.object<jstring>());
#endif
}

#if defined(Q_OS_ANDROID)

void Vibrator::vibrate(int milliseconds) {
    if (vibratorService.isValid()) {
        jlong ms = milliseconds;
        jboolean hasvibro = vibratorService.callMethod<jboolean>("hasVibrator", "()Z");
        vibratorService.callMethod<void>("vibrate", "(J)V", ms);
    } else {
        qDebug() << "No vibrator service available";
    }
}

#else
void Vibrator::vibrate(int milliseconds) {
    Q_UNUSED(milliseconds);
}

#endif

 

now you have to expose the class to QML:

#include "vibrator.h"
...
Vibrator vibrator;
engine.rootContext()->setContextProperty("Vibrator", &vibrator);

 

voila! its ready to use!

Vibrator.vibrate(500)

 

Enjoy

How to deal with dynamically created QQuickItem’s

Today I’d like to share some knowledge in form of small Qt C++/QML mixed project

The project is about chess game. Since its created for demonstration purposes, there is no battle mode, no AI and pieces moves checking missing some features such as en-passant etc

Code located here: ChessQML

Actually, inter-operate between C++ code and QML code in Qt framework pretty easy, however, there is few tips’n’tricks. For example: Make sure your objects’s pointer, created at C++ side and then passed to QML have to register its ownership to QML engine as C++ ownership:

QQmlEngine::setObjectOwnership(obj_ptr, QQmlEngine::CppOwnership);

This makes sense only for QObject’s derived classes

Please, leave your comments

 

Qt Quick Control’s TableView and C++ model using roles

Qt Quick Controls made big move forward in latest Qt releases. For example, in Qt 5.4 it takes native look on Android platform using styling option

Since it becomes more and more useful, its just waste of time to do not use it!

But its always there is some buts.

This time my stumbling-stone was TableView plus C++ data model

 

 

 

 

 

 

 

 

 

 

I’m not going to speechify a lot. Basically, standard scheme works, but my goal was to use roles as columns.In theory it was OK but every time I’ve met absence of data in my table. The only indicator that table works was increasing row counter

The problem was that roleNames() method of QAbstractItemModel class was not called. And the reason is that the method must be protected! For some reason this method in the Qt documentation as well as in tons of examples defined as public, and this is works in most cases but not for TableView!

 

QSettings and QML

Suffering from absence of useful QSettings in QML?

Its pretty easy to solve (if you not afraid of some c++ code in your project)

#ifndef SETTINGS_H
#define SETTINGS_H

#include <QObject>
#include <QSettings>

class Settings : public QObject
{
    Q_OBJECT
public:
    explicit Settings(QObject *parent = 0);
    Q_INVOKABLE void setValue(const QString & key, const QVariant & value);
    Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;

signals:

public slots:
private:
    QSettings settings_;
};

#endif // SETTINGS_H

 

#include "settings.h"

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

void Settings::setValue(const QString &key, const QVariant &value) {
    settings_.setValue(key, value);
}

QVariant Settings::value(const QString &key, const QVariant &defaultValue) const {
    return settings_.value(key, defaultValue);
}

register it:

    QQmlContext *context = engine->rootContext();
    context->setContextProperty("settings", &settings);

and use:

    FileDialog {
        id: fileDialog
        folder: settings.value("lastFolder", ".")
        onAccepted:  {
            settings.setValue("lastFolder", fileDialog.folder)
        }
    }

pretty easy, eh?

 

Load and control QML from C++

Ok folks, today we are talking about how to load custom QML file and integrate it into your main application? It is useful, for example, to create settings UI for different plugins, when each plugin requires its own UI

So, here is a code:

#ifndef QMLSETTINGSVIEW_H
#define QMLSETTINGSVIEW_H

#include <QObject>
#include <QQuickView>
#include <QQmlApplicationEngine>
#include <QQuickItem>

class QmlSettingsView: public QObject
{
    Q_OBJECT
public:
    QmlSettingsView(QObject *parent = 0);
    ~QmlSettingsView();
    QQmlApplicationEngine *engine() const;
    void setEngine(QQmlApplicationEngine *engine, const QString &qmlpath, const QString &finishedSignal);
    void showSettings();
    void hideSettings();
    bool setSettingsProperty(const char *name, const QVariant &value);
    QVariant settingsProperty(const char *name);

public slots:
    virtual void settingsFinished() = 0;

    QQuickWindow *parentWindow() const;

private:
    QQuickView *view_;
    QQmlApplicationEngine *engine_;
    QQuickItem *root_;
    QQuickWindow *parentWindow_;
};

#endif // QMLSETTINGSVIEW_H

 

#include "qmlsettingsview.h"
#include <QQmlContext>

QmlSettingsView::QmlSettingsView(QObject *parent):
    QObject(parent)
  , view_(0)
  , engine_(0)
  , root_(0)
  , parentWindow_(0){
}

QmlSettingsView::~QmlSettingsView() {
    if (view_)
        view_->deleteLater();
}

QQmlApplicationEngine *QmlSettingsView::engine() const {
    return engine_;
}

void QmlSettingsView::setEngine(QQmlApplicationEngine *engine, const QString &qmlpath, const QString &finishedSignal) {
    engine_ = engine;
    if (!engine_)
        return;

    if (view_) //already created
        return;

    engine_->clearComponentCache();
    if (engine_->rootObjects().count() <= 0)
        return;

    QObject *topLevel = engine_->rootObjects().value(0);
    parentWindow_ = qobject_cast<QQuickWindow *>(topLevel);

    if (!parentWindow_)
        return;

    view_ = new QQuickView(engine, parentWindow_);
    if (!view_)
        return;

    view_->setSource(QUrl(qmlpath));
    if (view_->status() != QQuickView::Ready) {
        return;
    }

    root_ = view_->rootObject();
    QString f_ = finishedSignal;
    f_ = f_.insert(0, "2");
    //settingsFinished() must be implemented in child class
    connect(root_, f_.toLatin1().data(), this, SLOT(settingsFinished()));
}

void QmlSettingsView::showSettings() {
    if (!view_)
        return;
    view_->show();
}

void QmlSettingsView::hideSettings() {
    if (!view_)
        return;
    view_->hide();
}

bool QmlSettingsView::setSettingsProperty(const char *name, const QVariant &value) {
    if (!root_)
        return false;

    return root_->setProperty(name, value);
}

QVariant QmlSettingsView::settingsProperty(const char *name) {
    if (!root_)
        return false;

    return root_->property(name);
}

QQuickWindow *QmlSettingsView::parentWindow() const {
    return parentWindow_;
}

The main purpose to create the code was to implement UI logic for separate plugins, that’s why its naming

Usage example:

#include "qmlsettingsview/qmlsettingsview.h"

class GrayScaleFilterPluginSettings: public QmlSettingsView {

    Q_OBJECT

public:
    GrayScaleFilterPluginSettings(QObject *parent = 0);
    virtual ~GrayScaleFilterPluginSettings();

    void settingsFinished();
signals:
    void finished();
};

define your new class somewhere in the main code:

GrayScaleFilterPluginSettings qmlsettingsview;

implementation

GrayScaleFilterPluginSettings::GrayScaleFilterPluginSettings(QObject *parent):
    QmlSettingsView(parent) {
}

GrayScaleFilterPluginSettings::~GrayScaleFilterPluginSettings() {
}

void GrayScaleFilterPluginSettings::settingsFinished() {
    emit finished();
}

connect finished signal to your main class slot, which will deal with the settings etc

connect(&qmlsettingsview, SIGNAL(finished()), this, SLOT(settingsClosed()));

here we show and hide our settings

void GrayScaleFilterPlugin::setupItem(QQmlApplicationEngine *engine) {
    if (!engine)
        return;

    qmlsettingsview.setEngine(engine, "qrc:/gssettings.qml", "finished()");
    qmlsettingsview.setSettingsProperty("width", qmlsettingsview.parentWindow()->width());
    qmlsettingsview.setSettingsProperty("height", qmlsettingsview.parentWindow()->width());
    qmlsettingsview.showSettings();
    return;
}

void GrayScaleFilterPlugin::settingsClosed() {
    qmlsettingsview.hideSettings();
}

setEngine() sets QML engine, path to your settings qml file and name of signal when the settings are gets closed.

You can read new properties in settingsClosed() slot and save them to file

 

That’s actually it at the moment

Feel free to ask a questions

 

plugin1

Do not hesitate to rework and clean up your code! Its always good practice to rethink what you have done before because everyone is evolving and what you thought best code solution yesterday, today becomes crappiest thing ever!

To help keep your code clean and organized let me introduce Qt plugins.

There is some documentation on how to create Qt plugins on Qt official site but lets go thru all steps again to make things clear.

So, step one: define plugin’s interface:

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QtPlugin>

QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE

class PluginInterface
{
public:

    virtual ~PluginInterface() {}

    virtual QString name() = 0;
    virtual QString description() = 0;

};

QT_BEGIN_NAMESPACE

#define PluginInterface_iid "org.cooldev.coolapp.PluginInterface/1.0"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
QT_END_NAMESPACE

#endif // PLUGININTERFACE_H

as you can see, plugin interface is pure virtual class. Macro Q_DECLARE_INTERFACE tells to Qt all that it need to create Qt plugin. For sure, PluginInterface_iid must be an unique identifier

Great news for QtCreator users. Latest QtCreator IDE has a template for creating Qt plugins: just go to File->New file or Project->Libraries->C++ Library. Press ‘Choose…’. Select Type as ‘Qt plugin’, choose an name, press Next, choose your Qt version, Next, choose your plugins class name and choose base class (any of them, you’ll remove it later). QtCreator will create an plugin implementation for you.

Make sure that your plugin implementation base classes are QObject and your interface class:

class MyFirstPlugin : public QObject, public PluginInterface {

another important thing is to put Q_INTERFACES declaration before public part of your plugin’s class declaration:

class MyFirstPlugin : public QObject, public PluginInterface {
 Q_OBJECT
 Q_INTERFACES(PluginInterface)

Now lets get back to .pro file. QtCreator will create needed lines in the file:

TEMPLATE = lib
CONFIG += plugin

Don’t forget about DESTDIR. Its important for packaging application for your destination platform

Ok. Plugin created and built. Now we have to load it from our application:

#include <QPluginLoader>

PluginLoader::load()
{
    QDir pluginsDir = QDir(qApp->applicationDirPath());
    pluginsDir.cd("plugins"); //good practice to put plugins into 'plugins' folder near your application

    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
            PluginInterface *pluginInstance = qobject_cast<PluginInterface*>(plugin);
            if (pluginInstance) {
                qDebug() << "Plugin file " << fileName << " loaded ok.";
                // now the plugin can be initialized and used
            } else {
                qDebug() << "Plugin file " << fileName << " loading fail";
            }
        }
        else {
            qDebug() << loader.errorString();
            qDebug() << plugin;
        }
    }
}

Two main points:

  • Qt tries to load every file in ‘plugins’ folder as Qt plugin
  • with casting loaded instance to your interface class you actually checking if the plugin is implementing exact this interface

That’s it for now

ps. Plugins can be derived from QObject, which makes possible to use signal-slot conception. As usual, there some tricks need to be done:

  1. Add your new plugin interface header file to HEADERS .pro file of your plugin implementation
  2. This works only for non-static Qt builds

Multithreading OpenGL in Qt 5

It always was a good prSpeedometer - Going Too Fastogramming practice that UI thread separated from working thread. Users doesn’t like when UI just freezes. These days, multithreading programming is not a rocket science and, fortunately, Qt have all that you need to create multuthreded applications. But what about OpenGL rendering in separate thread? What if you want OpenGL to do some off screen job for you while you interacting with user?

Here is some tips how to do this in Qt 5:

The main rule here is to create QOpenGLContext in the run() method of the OpenGL thread, otherwise any QOpenGL functions will not work. Unfortunately, playing with moveToThread() doesnt works (yet?)threadrip

If you planning to create several OpenGL threads within your application, don’t forget to call doneCurrent() method of QOpenGLContext. Then it makes sense to destroy context and recreate it in different thread. At least, this works pretty solid for me (Qt 5.1 for Linux)

QImage in QML

In this post I’ll show how to provide QImage from C++ code to QML

All we know, that Image {} element in QML supports only source property, which takes an URL as input. So how to put an QImage (or QPixmap or texture) to Image {}?

Answer is: QQuickImageProvider (in Qt 5)

First of all you have to create a so called image provider class, derived from QQuickImageProvider:

#include <QQuickImageProvider>

QT_BEGIN_NAMESPACE

class ImageProvider : public QQuickImageProvider
{
public:
explicit ImageProvider();
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
};

You have to reimplement method requestImage(). It takes an string id as input as well as requested image size.
String id is an unique id, generated in your QML code. We will come there later
If Image {} element request specific image size, you’ll get the size in requestedSize parameter. Just check it is it valid or not. If so, you have to resize your original image and return resized version. Also, you have to return new image size in the size parameter

Before using your image provider, you have to register it in QML engine:

ImageProvider *imageProvider = new ImageProvider;
QQmlApplicationEngine engine(QUrl("qml/main.qml"));
engine.addImageProvider("images", imageProvider);

in this case, “images” is an identifier for your image provider
Note: if you want to register several identifiers for several providers, you have to create separate object for each identifier:

QQmlApplicationEngine engine(QUrl("qml/main.qml"));

ImageProvider *imageProvider = new ImageProvider;
engine.addImageProvider("images", imageProvider);

ImageProvider *imageProvider1 = new ImageProvider;
engine.addImageProvider("images1", imageProvider1);

 

And, finally, last step. Adding Image element to QML code:

Image {
source: "image://images/" + id
cache: false
}

 

Take a look at source property.
In that URL image means that you will use an image provider. Then, images is provider identifier and id is the string value, which will be passed to your requestImage() implementation

Its important to turn cache off if you gonna to reuse an image id

That’s it. Hope this will help to someone

Last note: with the QQuickImageProvider class you can pass not only QImage but also QPixmaps and OpenGL textures to Image element

 

Very last note: do not try to use QSharedPointer<QImage>