Make your own slide show presentation in QML

To prepare my conference at Pas Sage En Seine [FR], a French hacking festival, I chose to write my slide presentation in QML.
It allows me to have better control and be free to do whatever I want (such as a timeline or any kind of animation).
Of course, That comes with a price. It is longer to do it that way but now I find some solutions. So, next time will be faster.

File hierarchy:

I preferred use QML through C++ Application. It provides more helpful feature, such as: the ability to make screenshots of your presentation at any time (useful as backup plan).
At the top level, you will found all C++ classes, project files and the main qml. Then, you will have a directory with all your pages and if it is required a directory with all your images.

├── cpphighlighter.cpp
├── cpphighlighter.h
├── deployment.pri
├── LICENSE
├── main.cpp
├── main.qml
├── pages
│   ├── 01_intro.qml
│   ├── 02_presentation.qml
│   ├── 03_jdr_et_rolisteam.qml
│   ├── 043_Exemple_code_1.qml
│   ├── 04_jdr_avantages_pb.qml
│   ├── 05_avantage_jdr_virtuel.qml
│   ├── 06_fonctionnalites_rolisteam.qml
│   ├── 07_rolisteam_debut.qml
│   ├── 08_Rolistik_a_Rolisteam.qml
│   ├── 10_frise_chronologique.qml
│   ├── 11_son_usage.qml
│   ├── 12_son_fonctionnement.qml
│   ├── 13_dice_parser.qml
│   ├── 14_themes_audio_3_pistes.qml
│   ├── 15_nouveaute_1_8.qml
│   ├── 16_projet_avenir.qml
│   ├── 17_reussites.qml
│   ├── 18_les_lecons.qml
│   ├── 19_objectif_rolisteam_libre.qml
│   ├── 20_FAQ.qml
├── pasSageEnSeine.pro
├── pasSageEnSeine.pro.user
├── qmlcontroler.cpp
├── qmlcontroler.h
├── qmlcontroler.ui
├── qml.qrc
├── README.md
├── rsrc
│   ├── all.png
│   ├── cc.png
│   └── chat.png

The C++ application

The main

It can be useful to see the state of the presentation and to read some extra notes about the current slide. To manage that, I wrote a small C++ application.
The first goal is to show the QML view, then add some features and communication between the QML view and the C++ window.

#include <QApplication>
#include <QQmlApplicationEngine>
#include "qmlcontroler.h"
#include <QQmlContext>
#include <QQuickTextDocument>

#include "cpphighlighter.h"

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

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("ScreenW",1280);
    engine.rootContext()->setContextProperty("ScreenH",720);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QmlControler ctr;
    ctr.setEngine(&engine);

    return app.exec();
}
main.cpp

Really easy, it loads the main.qml from the resources management system provided by Qt. It defines the targeted resolution by setting two constant into QML word: ScreenW and ScreenH.

In this project, the QmlControler class is the C++ window which provides slide feedback and additional information.

Let’s take a look to it:

Feedback window

This window is really simple. It has two parts: On the left, there is a label which displays screenshot of the qml view, and the right part is a QTextArea which display any additional note about the current slide.

void QmlControler::currentPageHasChanged(int i)
{
    m_currentScreen = i;
    QImage img = m_window->grabWindow();

    if(img.isNull())
        return;

    static int count = 0;


    img.save(tr("screens/%1_screen.png").arg(++count,3,10,QChar('0')),"png");
    qDebug() << "screen shot save" << count;

    m_ratioImage = (double)img.size().width()/img.size().height();
    m_ratioImageBis = (double)img.size().height()/img.size().width();

    m_label->setPixmap(QPixmap::fromImage(img));

    if((i+1>=0)&&(i+1<m_commentData.size()))
    {
        ui->textEdit->setHtml(m_commentData.at(i+1));
    }
    resizeLabel();
}
Current slide has changed

When the current slide has changed, the c++ window is notified thought the slot currentPageHasChanged, The application gets screenshot of the qml view, save it as a file, display it thought the label, then it looks for data about the current slide into the model. If any, there are displayed in the textedit.

Saving screenshots into file allows you to create a pdf file as backup plan for your presentation.

$ convert *.png mypresentation.pdf

 

QML Application

Loader system.

For readability reason, it is easier to have each page into one qml file. The application has to load those pages in the right order. To reach this goal, we have to define the order. I did it thank to a data model inside the main.qml file.
The main.qml displays all pages as item of a pathview. All items are loaded from the qt resource management system.

ListModel {
            id: panelModel
            ListElement {
                name: "Intro"
                path: "01_intro.qml"
                time: 1
                next: "Présentation de Rolisteam"
            }
First item of the model.

A page is mainly defined by two data: name and path. The path is the name of the qml file.
All other data are here as help, the time has not been used.

Then, the loader does its job, the key lines are the following:

    PathView {
        id: view
        anchors.fill: parent
        model: panelModel
        highlightRangeMode:PathView.StrictlyEnforceRange
        snapMode: PathView.SnapOneItem
        delegate:  Loader {
             source: "pages/"+path
        }
Path View

 

Table of Contents

To manage the table of contents, I added a listview with a model:

    ListView {
        id: listView1
        x: ScreenW*0.02
        y: ScreenH*0.3
        width: ScreenW/2
        height: ScreenH*0.2
        delegate: Item {
            width: ScreenW/2
            height: listView1.height/listView1.count
                Text {
                    color: view.currentIndex>=index ? "black" : "gray"
                    text: name
                    font.pointSize: ScreenH/48
                    anchors.verticalCenter: parent.verticalCenter
                    font.bold: true

                }
        }
        visible: view.currentIndex>0 ? true : false

        model: ListModel {
            ListElement {
                name: "Concepts"
                index:1
            }
            ListElement {
                name: "Chroniques"
                index:6
            }
            ListElement {
                name: "Logiciel"//système de build, code spécifique par OS.
                index:9
            }
            ListElement {
                name: "Bilan"
                index:15
            }
        }
    }
Table of contents in QML

Next slide

When you have many slides it can be helpful to have indication about the next one. I chose to display the title in the top-right corner. It was the easier way.

    Text {
        anchors.top: parent.top
        anchors.right: parent.right
        text: panelModel.get(view.currentIndex).next+">"
    }
Next slide

 

Design a page

Each page are independent but they are all based on the same pattern. In my case, they have a listview with model. Each item of the model is an point I should talk about it.

Each item has a index. The index is controlled with keyboard (down to increase, up to decrease). The page manages what is shown or hidden given the value of the index.

For example, the feature of dice alias has 10 as index. When the index page value becomes 10, the «Dice Alias»  item is displayed with an animation. Then, at 11, I can show a screen shot about the dice alias. At 12, the screenshot disappears and another text is displayed.

Position and Size

To ensure that all items will be display at the proper position and size.  I have based all computation on anchor or the screen size.

    Image {
        id: image1
        anchors.left: parent.left
        anchors.top: parent.top
        anchors.leftMargin: ScreenW*0.04
        fillMode: Image.PreserveAspectFit
        source: "qrc:/rsrc/Rolisteam.svg"
        width: ScreenW*0.2
    }
Display the logo at the right position and size.

Other way

There is a module that provides Items to create QML presentation. I don’t use it for this one but it may provide interesting things.

https://github.com/qt-labs/qml-presentation-system

Get the code

You are invited to clone the code at : https://github.com/obiwankennedy/pses

Leave a Reply

Your email address will not be published. Required fields are marked *