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