Qt Projects Develop cross-platform applications with modern UIs using the powerful Qt framework Marco Piccolino BIRMINGHAM - MUMBAI Qt Projects Copyright © 2018 Packt Publishing All rights reserved No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews Every effort has been made in the preparation of this book to ensure the accuracy of the information presented However, the information contained in this book is sold without warranty, either express or implied Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals However, Packt Publishing cannot guarantee the accuracy of this information Commissioning Editor: Kunal Chaudhari Acquisition Editor: Siddharth Mandal Content Development Editor: Arun Nadar Technical Editor: Surabhi Kulkarni Copy Editor: Safis Editing Project Coordinator: Sheejal Shah Proofreader: Safis Editing Indexer: Tejal Daruwale Soni Graphics: Jason Monteiro Production Coordinator: Shantanu Zagade First published: February 2018 Production reference: 1210218 Published by Packt Publishing Ltd Livery Place 35 Livery Street Birmingham B3 2PB, UK ISBN 978-1-78829-388-4 www.packtpub.com mapt.io Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career For more information, please visit our website Why subscribe? Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals Improve your learning with Skill Plans built especially for you Get a free eBook or video every month Mapt is fully searchable Copy and paste, print, and bookmark content PacktPub.com Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy Get in touch with us at service@packtpub.com for more details At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks Contributors About the author Marco Piccolino is a consultant, technical trainer, and speaker developing Qt apps for businesses and consumers on a daily basis He is the founder of the QtMob Slack chat, a community of Qt application developers with a focus on mobile, resource sharing, and problem-solving Marco's main professional interests include application architecture, test-driven development, speech, and language technologies, and everything Qt I am grateful to the technical reviewers, Juergen Bocklage-Ryannel and Pierre-Yves Siret, for their insightful comments and thought-provoking suggestions I would also like to thank Siddharth Mandal, Arun Nadar, Surabhi Kulkarni, and the whole Packt team that worked on the book, improving it in various ways, from code to language Finally, I would like to thank my colleagues, my parents, and my wife Silvia for their support Data transport between app and browser with WebChannel One piece of the puzzle is still missing, that is, how we interact, within a standard web page, with objects that might have been created on the C++ or QML side? A dedicated Qt module — QtWebChannel — comes to the rescue (http://doc.qt.io/qt-5.9/qtwebchannelindex.html) The concept is simple; you register with the WebChannel any objects that you want to have available in your client JavaScript environment Once this is done, these objects will be accessible from the JavaScript code, including their signals, properties, and so on In our case, we want the HTTP receiverChannel instance implemented in the previous sections to be available in the HTML page provides communication between a JavaScript client (including a remote browser, a Qt WebEngine view, or a QML environment) and a C++ or QML server It does so by leveraging the web technology known as web sockets The client just needs to have support for web sockets and load the qwebchannel.js JavaScript library The server also needs to implement a custom transport based on Qt WebSockets (http://doc.qt.io/qt-5.9/qtwebsockets-index.html) if this is not already provided QtWebChannel Luckily, QtWebEngine provides out-of-the-box support for QtWebChannel, and the transport layer between the two is already implemented and ready to use To add it to the cmmonitor project, a couple of steps are required First, we will add the module to cmmonitor.pro: # cmmonitor.pro QT += quick charts webengine webchannel Then, we'll have to create a QQmlWebChannel instance and expose it to the QML engine: If the objects you want to expose to the web browser are implemented in QML, you could use the QML WebChannel type instead // cmmonitor/main.cpp #include int main(int argc, char *argv[]) { auto receiverChannel = new channels::ReceiverHttp(&app); QtWebEngine::initialize(); qRegisterMetaType(); auto defaultWebChannel = new QQmlWebChannel(&app); defaultWebChannel->registerObject(QStringLiteral("receiverChannel"), receiverChannel); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("receiverChannel",receiverChannel); engine.rootContext()->setContextProperty("defaultWebChannel",defaultWebChannel); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); } Now, the receiverChannel object is registered on defaultWebChannel, with the receiverChannel ID Once this is done, we should tell the WebEngineView QML component to make use of defaultWebChannel This is achieved by simply setting the webChannel property, as follows: // cmmonitor/main.qml import QtQuick 2.9 import QtQuick.Window 2.2 import QtWebEngine 1.5 Window { WebEngineView { id: readingsChartJS anchors.top: readingsChart.bottom width: parent.width height: parent.height / url: "qrc:///ReadingsChartJS.html" webChannel: defaultWebChannel } } There we go! At this stage, we can focus on the HTML side and import the qwebchannel.js client The library does not need to be bundled explicitly with our application; it is enough that it is included by pointing at the specific QRC path qrc:///qtwebchannel/qwebchannel.js: ReadingsChartJS Once the JS library is included, we can create an instance of the QWebChannel object, where we define a transport object to be used for server-client communication and a callback to be invoked once the QWebChannel has been properly initialized Since WebEngineView supports out-of-the-box a pre-implemented transport object called qt.webChannelTransport, we will use that one To know how to implement custom transport objects, you can take a look at http://doc.qt.io/qt-5.9/qtwebchannel-javascript.html In the callback function, we can reference the receiverChannel instance and add any code that should be executed, for example, in response to the readingsProcessed signal being emitted: new QWebChannel(qt.webChannelTransport, function(channel) { window.receiverChannel = channel.objects.receiverChannel; receiverChannel.readingsProcessed.connect(function() { // call charting functions }); }); We shortened the reference to receiverChannel by making it globally accessible and added a callback function to the readingsProcessed signal with the connect method We can now add an HTML5 chart to the document and update it every time readingsProcessed is fired Adding an HTML5 time series We should now decide upon a charting library based on HTML5 and JavaScript to use Although there are many options available, Chart.js (http://www.chartjs.org/) is ideal because of its permissive MIT license and relatively simple APIs Starting from the QML graph example of Chapter 8, Building a Mobile Dashboard to Display Real-Time Sensor Data, we will re-implement it with Chart.js I won't go into the details of the re-implementation since this is out of scope for this title — you can check out the Chart.js documentation and samples to get the specifics Besides Chart.js, we'll be using Moment.js, which fully integrates with the charting library for the easy handling of dates and times The following is the code that produces a chart similar in appearance to the QML one we created in Chapter 8, Building a Mobile Dashboard to Display Real-Time Sensor Data The main difference is only that for brevity's sake, the HTML5 version does not implement the seconds running when there is no incoming data: var date = moment(Date.now()-15000); var chartLabels = [date]; var chartData = [null]; var i = 0; while (i < 15) { date = date.clone().add(1, 'seconds'); chartLabels.push(date); chartData.push(null); ++i; } var ctx = document.getElementById('my-chart').getContext('2d'); var chart = new Chart(ctx, { type: 'line', data: { labels: chartLabels, datasets: [{ label: 'mockSensor1', data: chartData, type: 'line', borderColor: 'orange', backgroundColor: 'rgba(0,0,0,0)' }] }, options: { elements: { line: { tension: 0, fill: false } }, scales: { xAxes: [{ type: 'time', distribution: 'series', ticks: { source: 'labels' }, time: { unit: 'second', displayFormats: { second: 'H:mm:ss' } } }] } } }); function addData(chart, label, data) { chart.data.labels.push(label); chart.data.datasets.forEach((dataset) => { dataset.data.push(data); }); chart.update(); } function removeData(chart) { chart.data.labels.shift(); chart.data.datasets.forEach((dataset) => { dataset.data.shift(); }); chart.update(); } new QWebChannel(qt.webChannelTransport, function(channel) { }); As you can note in the preceding code, Chart.js uses canvas to perform the painting The Chart instance requires a canvas context and a nested configuration object to be specified, where the data, labels, and visual aspects of the chart are defined The following is how the empty JS line chart should look like: Given how the API of Chart.js works, to update the chart with the sensor data, we will need to add two methods, one that removes the first point in the dataset (we'll call it removeData) and one that adds a new point at the end of the dataset (let's call it addData), and then call the update function to refresh the drawing We will be invoking these two methods in the callback function that is triggered every time readingsProcessed is fired In QtWebChannel, the arguments of readingsProcessed can be accessed through the arguments variable Here is the updated code: var chart = new Chart(ctx, { }); function addData(chart, label, data) { chart.data.labels.push(label); chart.data.datasets.forEach((dataset) => { dataset.data.push(data); }); chart.update(); } function removeData(chart) { chart.data.labels.shift(); chart.data.datasets.forEach((dataset) => { dataset.data.shift(); }); chart.update(); } new QWebChannel(qt.webChannelTransport, function(channel) { window.receiverChannel = channel.objects.receiverChannel; receiverChannel.readingsProcessed.connect(function() { if (arguments[0][0]) { removeData(chart); addData(chart, arguments[0][0]["timestamp"], arguments[0][0]["value"]); } }); }); Note how the QVariantList returned by readingsProcessed is automatically converted to a JavaScript object (arguments[0]), as it happens in QML If you now run cmmonitor, you should not see the chart updating since cmbroadcast is not running However, when you first run cmbroadcast (which should be running the HTTP BroadcasterChannel as shown in the previous sections) and then run cmmonitor, you'll see both the QML chart and the HTML5 chart updating as shown in the screenshot, possibly at slightly different speeds: The style of the two components is still a little different, feel free to tweak either of them so that they become more similar Summary In this chapter, we built upon the work we did in Chapters 7, Sendinging Sensor Readings to a Device with a Non-UI App, and Chapter 8, Building a Mobile Dashboard to Display Real-Time Sensor Data, by augmenting our sensor dashboard application with two core features: Support for the HTTP channel to sensor data transmission Use of web technology to create an alternative charting UI By doing this, we engaged with several new Qt modules and APIs — Qt Network, QtWebEngine, and QtWebChannel — and also made good use of the third-party QHttp project This chapter has shown you how Qt, while still not being a viable choice for implementing UIs in the browser (but things are changing, see Appendix Additional and Upcoming Qt Features for that), has got a firm foot in the web world, and you can take advantage of it to cover many different requirements Additional and Upcoming Qt Features By now, you should have a grasp of Qt's features and API's extent Given the limited breadth of this book, I did not have a chance to introduce you to all the currently available and upcoming Qt APIs I chose only those APIs that seemed the most relevant because of either their widespread usage or their novelty In this section, I will briefly introduce you to other current Qt APIs that you may need for your daily work, and to the new and upcoming Qt features beyond what is provided by Qt 5.9 Long Term Support (LTS) For an overview of all the modules available for each version, check out https://doc.qt.io/qt-5.9/qtmodules.html, substituting the appropriate minor version Alongside general-purpose modules, you will find all sorts of specialty modules, which are either mostly interesting for specific kinds of applications, or only supported on a limited number of platforms Also, keep in mind that there are other Packt titles and third-party resources that provide coverage and sample projects for some of the technologies mentioned in the coming sections Additional Qt features in 5.9 LTS Among the technologies we mentioned, the Qt SQL module (https://doc.qt.io/qt-5.9/qtsql-index.html) is most likely something you will deal with, or at least consider, when looking for a persistence mechanism or connecting with already-existing databases It provides drivers for different database technologies A list is available on http://doc.qt.io/qt-5.9/sql-driver.html Qt Quick also provides an integrated local storage mechanism, similar to what you find in modern web browsers, based on SQLite; for more details on Qt Quick, refer to http://doc.qt.io/qt-5.9/qtquick-localstorage-qmlmodule.html Another, more lightweight, option to consider when in need of persisting data is the QSettings class ( http://doc.qt.io/qt-5.9/qsettings.html—also available in QML), which provides file-based, platform-specific backends It is often a valid choice to retain local configuration settings specified by the user Qt also provides first-class multithreading facilities These are available through a few different APIs, which cater for both low-level and high-level control Qt Concurrent (https://doc.qt.io/qt-5.9/qtconcurre nt-index.html) provides a high-level API, whereas a few Qt Core classes can be used for more finegrained control For a complete overview and comparison, check out http://doc.qt.io/qt-5.9/threads-technologies html When planning your application architecture or specific components, you may find it helpful to conceptualize some aspects in terms of Finite State Machines (FSMs) Qt provides APIs for FSMs in C++ and QML/JS; check out more details on these at http://doc.qt.io/qt-5.9/statemachine-api.html Starting with Qt 5.8, it also supports SCXML-based FSM specifications, which can be parsed to generate the corresponding C++ or QML/JS code; check out more details on these at https://doc.qt.io/qt-5.9/qtscxml-index.ht ml The Qt Positioning and Qt Location modules (https://doc.qt.io/qt-5.9/qtlocation-index.html) provide a set of classes for both retrieving and manipulating position data and other geographic entities and for displaying map data, with an emphasis on QML integration To write dynamic UIs, another technology worth exploring is Qt Quick's animations and transitions (http://doc.qt.io/qt-5.9/qtquick-statesanimations-animations.html) Thanks to the power of QML property bindings and the OpenGL backend, you will be able to create more complex animations of shape, color, and many other kinds of properties in no time A very good introduction to what can be achieved with Qt Quick animations is provided by the QML Book at https://qmlbook.github.io/en/ch05/index.html #animations Qt Quick Controls also supports a styling mechanism (https://doc.qt.io/qt-5.9/qtquickcontrols2-styles.html) that helps you achieve platform-dependent or completely customized looks easily Besides these features, there are also a few technicalities we didn't have time to explore in the book, including how to provide extension capabilities to your applications by creating plugins (http://doc.qt.io/qt -5.9/plugins-howto.html) and a few more As usual, the official Qt documentation is your best friend New and upcoming Qt features Although Qt 5.9 LTS focused on consolidating existing features and bugfixes by providing a solid and up-to-date development platform, subsequent Qt versions make it possible to take advantage of a cutting-edge functionality Recently, the expanding markets of In-Vehicle Infotainment (IVI) and digital cockpits, industrial automation, and the Internet of Things (IoT) have steered many areas of development Beyond the already-existing generic offering for application development and embedded devices, developers, and businesses have now access to specific commercial feature bundles for their industry of choice, including Qt for Automotive (https://www.qt.io/qt-in-automotive) and Qt for Automation (https://www.qt.io/qt-in-automation/) Among the most notable recent additions to the Qt distribution are a couple of enhancements on the UI side Qt Quick Controls now provides a style called Imagine with out-of-the-box support for Controls graphic assets (http://doc.qt.io/qt-5/qtquickcontrols2-imagine.html) This feature makes it really easy to export assets for use in Qt Quick UIs from design programs, such as the Adobe Suite or Sketch Another enhancement in the Qt Quick world is the ability to define arbitrary shapes simply using QML types (refer to https://doc.qt.io/qt-5/qtquick-shapes-example.html) When it comes to multitouch interaction and gestures, the Qt Quick Pointer Handlers (http://doc.qt.io/qt-5/qtquickhandlers-index.html) promise great improvements over previously available solutions The addition of the Qt 3D Studio graphical tool and runtime makes it easier to create and embed 3D content, with support for the Qt 3D module being added A new platform plugin makes it possible to stream graphics content in a browser via WebGL ( http://blog.qt.io/blog/2017/07/07/qt-webgl-streaming-merged/), and a web assembly platform plugin is also in the works In terms of connectivity and I/O, Qt MQTT (http://doc.qt.io/QtMQTT/index.html) and Qt Remote Objects (a package for high-level interprocess communication available at https://doc.qt.io/qt-5/qtremoteobjects-index.html, already in 5.9 as a technical preview) provide further options particularly suited for embedded distributed applications Finally, the Qt Speech module (https://doc.qt.io/qt-5/qtspeech-index.html, currently in technical preview) will provide a common frontend for open source and commercial text-to-speech (TTS) and speech-to-text (STT or ASR) solutions TTS support is already available for some backends on selected platforms Ensure that you check out the official blog of The Qt Company (http://blog.qt.io) to keep up to date with the new features Other Books You May Enjoy If you enjoyed this book, you may be interested in these other books by Packt: Mastering Qt Guillaume Lazar, Robin Penea ISBN: 978-1-78646-712-6 Create stunning UIs with Qt Widget and Qt Quick Develop powerful, cross-platform applications with the Qt framework Design GUIs with the Qt Designer and build a library in it for UI preview Handle user interaction with the Qt signal/slot mechanism in C++ Prepare a cross-platform project to host a third-party library Build a Qt application using the OpenCV API Use the Qt Animation framework to display stunning effects Deploy mobile apps with Qt and embedded platforms Computer Vision with OpenCV and Qt5 Amin Ahmadi Tazehkandi ISBN: 978-1-78847-239-5 Get an introduction to Qt IDE and SDK Be introduced to OpenCV and see how to communicate between OpenCV and Qt Understand how to create UI using Qt Widgets Learn to develop cross-platform applications using OpenCV and Qt Explore the multithreaded application development features of Qt5 Improve OpenCV application development using Qt5 Build, test, and deploy Qt and OpenCV apps, either dynamically or statically See Computer Vision technologies such as filtering and transformation of images, detecting and matching objects, template matching, object tracking, video and motion analysis, and much more Be introduced to QML and Qt Quick for iOS and Android application development Leave a review - let other readers know what you think Please share your thoughts on this book with others by leaving a review on the site that you bought it from If you purchased the book from Amazon, please leave us an honest review on this book's Amazon page This is vital so that other potential readers can see and use your unbiased opinion to make purchasing decisions, we can understand what our customers think about our products, and our authors can see your feedback on the title that they have worked with Packt to create It will only take a few minutes of your time, but is valuable to other potential customers, our authors, and Packt Thank you! .. .Qt Projects Develop cross- platform applications with modern UIs using the powerful Qt framework Marco Piccolino BIRMINGHAM - MUMBAI Qt Projects Copyright © 2018 Packt... from Qt Creator The training videos (https://www .qt. io /qt- training-materials/) and self-study pack (https://www .qt. io /qt- training-m aterials/) at qt. io The Qt Company's blog (http://blog .qt. io/),... use cases Setting up the project Prototyping the UI Introducing Qt Widgets Using Qt Widgets Designer Adding the main layout Adding the left column and the text editor Adding the List View, button,