[DSP] Getting started with Rust and QML

This is a part of my Daj się poznać / Get Noticed! 2017 series. It is for a contest where I have to write a blog post twice a week abd create a open source project. Read more about it here.

The time has come for my project to enter UI part development. Just as a reminder, I develop application for encrypting and decrypting files using public-key cryptography, so they can be safely sent over insecure channels, such as emails. Its goal is to be user-friendly enough to be used by pretty much anyone who can use the email client.

As I mentioned in the introductory post, I planned to use Qt for GUI part, as I like how it looks and I have some (very limited) experience in writing code in it. As I recall, last time was a MD5 brute-force breaker I had to write to some security related class at the university. So probably some 5 years ago.

Of course, many things have changed since then. One of most important changes in my opinion is introduction of QML. It’s expanded as “Qt Meta Language” or “Qt Modeling Language” and, to repeat after the website:

It defines and implements the language and engine infrastructure, and provides an API to enable application developers to extend the QML language with custom types and integrate QML code with JavaScript and C++.

Of course, luckily, due to heavy work from open-source community, we are not limited to C++ and JavaScript, because they are both languages I’d rather not use ever again. But language discrimination aside, I concentrate on QML bindings to Rust. There are actually two of them:

  • qmlrs is a bit less maintained, has version 0.1.1 in crates.io and is written in mixture of Rust and C++.
  • qml-rust is a bit different. It’s based on the project called DOtherSide, which is C library for creating bindings to QML. Right now it supports such bindings for Rust, D and Nim, which sounds pretty cool.

I tried both of them in a simple example I’m going to show below and they feel pretty much the same on the surface. For now, I decided to go with the latter: I like it being more generic and it promises to work somehow on Windows (which is quite serious requirement for me). I’m not 100% sold though and might turn to the other one. Especially concerning is a failing build in the CI at the time of writing this post. But maybe it’s just one of Travis things we all know and “love”.

Building basic example

To check how to start with Rust and QML, I decided to try and compile an example that was given to me by Qt Creator when I created my first Qt Quick project. Qt Quick is a set of standard components for QML development. The program consists of two buttons, which we can click and appropriate message appears in new alert window. Nothing fancy, but enough to have something running that is more verbose than just an empty window.

First of all, I copied two QML files Qt Creator generated:

main.qml:

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("&Open")
                onTriggered: console.log("Open action triggered");
            }
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }

    MainForm {
        anchors.fill: parent
        button1.onClicked: messageDialog.show(qsTr("Button 1 pressed"))
        button2.onClicked: messageDialog.show(qsTr("Button 2 pressed"))
    }

    MessageDialog {
        id: messageDialog
        title: qsTr("May I have your attention, please?")

        function show(caption) {
            messageDialog.text = caption;
            messageDialog.open();
        }
    }
}

and MainForm.ui.qml:

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2

Item {
    width: 640
    height: 480

    property alias button1: button1
    property alias button2: button2

    RowLayout {
        anchors.centerIn: parent

        Button {
            id: button1
            text: qsTr("Press Me 1")
        }

        Button {
            id: button2
            text: qsTr("Press Me 2")
        }
    }
}

I’m not going to go through them in detail, because a) I’m no QML expert (yet ;) ) and b) the feel pretty much self-explanatory to me. Important thing to note is that not only visual components hierarchy is defined here, but also some parts of the logic, like binding functions to click events on buttons.

With that, there is really not much to write on Rust side:

#[macro_use]
extern crate qml;

fn main() {
    let mut engine = qml::QmlEngine::new();
    engine.load_file("src/main.qml");
    engine.exec();
    engine.quit();
}

And that’s it. The result look like this:

As I mentioned, nothing fancy, but generates a bit of joy. Especially for someone who does not usually work with graphical interfaces. And of course, you can find the code used for this example here.

Related posts