QML CachingLoader: Caching loaded pages

TL;DR: When switching back and forth between pages in a QML UI, caching the contents speeds up the loading time of the pages. When writing QML, using a Loader can come in handy: Certain UI elements are loaded in a deferred way, e.g. not at app startup, but when the user clicks a button. When alternating between source elements of a Loader, the old component will always be deleted, as the documentation states: "Setting source to a new URL will also cause the item created by the previous URL to be unloaded." This might not always be what the user wants, so we have written a CachingLoader component, which (you guessed it) caches all components that have been loaded before: https://github.com/edelhirsch/cachingloader For benchmarking the code the above repository loads 2 pages with big images to simulate non-trivial loading time of sub-pages. The test shows that for the first time when a page is loaded, all three ways of deferred loading (Loader with "source" property, Loader with "sourceComponent" property, CachingLoader) behave the same. However, when a previously loaded page is loaded again, the Loader object has to re-read it from disk. The CachingLoader has not unloaded it, but just restores it from the cache for immediate displaying without reading anything from disk: In this example there is no real difference when loading files via the "source" or "sourceComponent" attribute, the slight differences seem to be only variation between measurements. Memory usage is a bit harder to measure, because QML does not seem to release the deleted pages right away, but waits for the garbage collector to kick in. However, in general the CachingLoader is trading loading time vs. memory usage, which means when using the CachingLoader the memory usage will be higher. A normal Loader object can release the memory of previously loaded pages, while the CachingLoader keeps all pages in its cache. The next steps for the CachingLoader would be to introduce a "property bool isCacheable" to have more control about whether pages should be cached or not. Small caveat: When the CachingLoader caches one of its pages, it sets its "enabled" attribute to false, which means it won't receive no more mouse and keyboard events (when loading it from the cache the attribute is of course set to true again). However, care must be taken for other activity coming from e.g. Connections attributes; those should probably made active only when the root page is active.

KDAB Challenge Solutions

Task 1

View Task 1

Proxy types can be tricky. If we got a QChar (or a reference to a QChar) by accessing a character in a QString with the operator[] as most people would expect to, the automatic type deduction requested by auto current = hello[i] would deduce that current is of type QChar.

But QString::operator[] does not return a QChar. It returns a QCharRef. Even if we think of it as a reference to a QChar, the compiler does not, and the automatic type deduction can not remove the reference part like it would if the return type was a proper reference (QChar&).

This means that current will be a value of type QCharRef. When we modify it, it will modify the original string (contrary to what most people expect because of C++’s value semantics).

One of the solutions here is not to use automatic type deduction and explicitly specify the type of current to be QChar.

    QChar current = hello[i];

Another thing that could help is to declare the hello string to be const. It is a good practise to use const by default when declaring variables.

The second issue in the first task was that the original string ends with an exclamation mark, while the string in the Q_ASSERT does not.

Task 2

View Task 2

The problem in the second task is similar to the previous one. When we see strings being concatenated, we assume that the result is also a string.

String concatenation is slow (you can check out this post for more info) and Qt allows us to activate delayed (lazy) concatenation by defining QT_USE_QSTRINGBUILDER. Instead of operator+ returning a string, it will return a class called QStringBuilder which will keep references to all strings we want to concatenate and perform the concatenation only when we convert it to a QString.

This means that when we use the automatic type deduction – auto message = ... – we get a message variable that is not a string, but rather an object that keeps references to all the strings we want to concatenate. When we try to print it out with qDebug, it will concatenate all the strings and print out the result.

The problem is that one of the references in our example will be a dangling reference – reference to a temporary string returned by the tr function that has been destroyed before the actual concatenation is performed. So, we get undefined behavior (most likely a crash in this case).

This is easily fixed by explicitly specifying the type of message to be a QString. This will perform the concatenation before the temporary string returned by the tr function is destroyed.

Task 3

View Task 3

The final task is quite different to the previous ones. It shows a function implemented with two for loops nested into each other. The time complexity of the function is O(m*n) where m is the length of xs and n is the length of ys. The memory complexity is O(1).

If we analyze the function, we can deduce that it counts all the items in xs that are smaller than or equal to the smallest value in ys. While the provided example uses sorted vectors, it is obvious that this function also works for unsorted vectors.

One approach (a frequently submitted one) to solving this using the algorithms found in the standard library is to sort both collections and then use the lower_bound to find the first element in (now sorted) xs that is not smaller than the smallest element in ys (ys[0] after sorting). We can then use std::distance to get the count how many elements we have between xs.cbegin() and the item we just found.

The time complexity of this solution is O(n log n + m log m) which is better than the original implementation, but the memory complexity grew to O(m + n) because we need to copy the original vectors in order to sort them, which is significantly worse.

If we go a bit deeper, we can see that we are using just ys[0] so we don’t really need to have the whole vector sorted. We just need the smallest value in ys. We can find this in linear time with the std::min_element algorithm.

With this, we would end up with O(m log m + n) time complexity and O(m) memory complexity, as we are still sorting the xs. Better, but not good enough.

Now the question is whether we really need to sort the xs?

If we know the minimum of ys we need to compare xs against, it is much cheaper just to go through all the unsorted xs one by one and check which ones are smaller than to sort the xs first. This can easily be done with std::count_if:

    int counting(const std::vector<int>& xs, const std::vector<int>& ys)
    {
        if (ys.empty()) return xs.size();

        const int min_y = *std::min_element(ys.begin(), ys.end());
        return std::count_if(xs.begin(), xs.end(), [=] (int x) {
                return x <= min_y;
            });
    }

The time complexity of this solution is O(m + n) and the memory complexity is O(1) which is the best we can do for this problem.

The post KDAB Challenge Solutions appeared first on KDAB.

gbgcpp – Ribbons using Qt

I’ve been involved in the gbgcpp group, a part of the larger Sweden C++ community, for a couple of years. It is fun to see that there is a lot of C++ developers out there, once you start looking for them.

In the next meetup, this Wednesday, there will be both C++ and Qt. The topic is to implement Ribbons in Qt, based on a seminar by Dag Brück. If you happen to be in the vicinity of Gothenburg, I recommend you to go there!

I’d also like reach out and thank Sylog for hosting the event!

Qt World Summit Training – Berlin 2019

At Qt World Summit in 2019, KDAB offered five Introductory courses (one was given by our partner, froglogic), and three advanced classes., as follows:

Introductory Course descriptions

Introduction to Qt 3D Studio, trainer: Nuno Pinheiro

This training introduces designers and developers to 3D content workflows and concepts, giving them a solid grounding in creating content using Qt 3D Studio, achieving the visual results they require, and integrating their work with other Qt content such as Qt Quick.

Existing 2D and 3D designers, user-experience designers, as well as developers working on visuals, will all benefit from learning the features and workflow offered by Qt 3D Studio. The training includes a large amount of hands-on time with the software, giving students confidence to begin creating their own content immediately, taking full advantage of the core features available.

Why learn Qt 3D Studio?

Qt 3D studio gives a tool-led workflow for integrating 3D content into Qt and QtQuick. It provides a simple environment for structuring 3D content, defining animations and behaviors, specifying materials and visual effects, and exporting complete presentations to an optimized runtime component.

While a wide range of workflows are possible when integrating 3D content, this training allows you and your team to focus on the best-practice approaches when working with Qt 3D Studio, to give a robust and well-defined path from 3D content into your final product.

Target audience: Principally designers, or developers who need to get an overview of QML integration. Prerequisite: No coding experience required, some familiarity with 3D concepts would be useful.

About Nuno

Senior UX/UI designer at KDAB, Nuno did the first QML training for designers and actively uses the QML language for fast UX/UI prototyping and UI solutions deployment. His works include general illustrations, UI design, corporate design, interactive mock-ups, animation examples and much more. Known for his contribution to the award winning Oxygen Project where he is the current coordinator, his computer art is used on KDE computer platforms worldwide. Nuno has an MSc in Civil Engineering.

 

Introduction to CMake, trainer: Kevin Funk

CMake is the de facto standard build system for C and C++ outside of frameworks that require their own. It has earned this place by supporting the situations and special cases that arise in real projects.

Support for CMake within Qt is being significantly improved and there are longer term plans to switch to CMake for building Qt itself. It’s currently a good alternative if you hit limitations in qmake.

This course will teach the basics of creating and building projects with CMake. In recent years, CMake has introduced some cleaner and more precise constructs. The course will focus on the new constructs where possible.

Why learn CMake?

CMake has broad functionality that covers many real world problems. Learning CMake enables you to solve advanced build requirements. This includes cross-platform builds, feature detection based on platform or available libraries, built- time configurable feature switches and custom build steps. CMake is increasingly widely adopted across the industry.

Target audience: C and C++ Developers who are interested in how to build their code. Prerequisite: Experience with build systems.

About Kevin

Kevin has actively developed with Qt/C++ since 2006 and has a special interest in tooling and profiling. He’s an active contributor to KDAB’s GammaRay analyzer (a high-level Qt application debugger) and has a strong emphasis on state machine tooling. He is co-maintainer of the KDevelop IDE, a powerful C/C++ development environment backed by Clang, and is pushing for cross-platform success inside KDE. Kevin holds a Masters Degree in Computer Science.

 

Introduction to Qt/QML, trainer: Jan Marker

This training is an introduction to Qt Quick. On the one hand it will teach you how to compose fluid user interfaces with slick animations using the QML language. On the other hand it will teach you how you hook the QML side up to your business logic in C++.

  • Course contents:
  • Connecting a QML UX with C++ business logic
  • Complex list views including data provided from C++ models
  • Custom objects implemented using Qt Quick scene graph
  • Profiling and best practices for optimal performance
Why learn Qt QML?

Designed to take people new to Qt or QML, from the basics to a deep functional understanding of best practices, this Qt/QML training will equip you with the skills and know-how to boost your productivity at work.

Target Audience: Developers and managers interested in learning the autonomy of a QML application. Prerequisite: Knowing the basics of Qt at C++ level is an advantage but not a requirement.

About Jan

Software engineer at KDAB, Jan has been using Qt since 2009 when he started contributing to the KDE project. Since joining KDAB he has worked on multiple large Qt and QML projects, while more recently also developing Wayland compositors. Besides in-depth knowledge of Qt and C++, Jan also has a deep interest in other technologies like NodeJS. He holds a BSc in Computer Science.

 

Multithreading in Qt, trainer: András Mantia

Multithreaded programming is essential for developers to create fast and responsive applications on computers, phones and embedded devices, all with an increasing number of cores. Qt offers several mechanisms for multithreading; however, it can be difficult to know which to use and how to steer clear of common pitfalls. This course offers guidance for writing safe and efficient multithreaded code with Qt.

Why learn about Multithreading with Qt?

Multithreaded development is a complex subject where it is easy to write code that contains severe bugs yet looks correct. This training will provide a solid foundation for writing safe and effective multithreaded code in Qt applications.

Target audience: Qt Developers interested in multithreading programming. Prerequisite: Knowledge and experience programming with Qt and C++. A basic understanding of multithreaded programming is an advantage but not required.

About András

Senior software engineer at KDAB. András has actively developed with Qt since 2002 and is a core developer of KDE’s web development environment Quanta Plus and contributor to other parts of KDE. He talks at free software events about Qt-based products and has held training courses for companies such as Accenture, TietoEnator and Nokia.

 

Qt GUI Testing with Squish, trainer Jakub Topolski, froglogic

In order to achieve high quality applications during testing process all the functionality of the software shall be covered, including fully exercising GUI itself. For regression testing automating this process gives benefits, saving execution time and increasing accuracy. On the other hand, GUI Automation might be a challenge, as GUI may change significantly during a product life cycle. In this course we learn how to design and implement cross-platform automated tests using Squish GUI Tester for  Qt, QML & QtQuick applications that continue to work as your product evolves.

You will learn:

  • Introduction to GUI Testing
  • Squish Overview (installation, configuration)
  • Test Script Creation and Execution
    • Recording and Replaying Test Scripts
    • Verification Points (Properties, Screenshot, Visual)
    • Test Results and Logging
    • Squish API
    • Image-Based Lookup
  • Development of Test Cases at Business Level
  • Set-Up and Tear-Down Functions
  • Debugging Test Scripts
  • Object Recognition
  • Accessing Application Internals (Inspecting, Object Properties and Methods)
  • Synchronisation and Event Handling
  • Squish Command-Line Tools
  • Working with Multiple Applications
  • Hooking into Running Applications
  • Squish Integration with CI

Prerequisites: The course is for developers and testers already familiar with the basic concepts of Qt.

About Jakub

Jakub has worked in Quality Assurance since 2012. Over the years he has gained experience in manual, automatic and performance testing. A Python enthusiast, Jakub joined froglogic in 2016 to support Squish users, conduct trainings and consult. He graduated from the Gdansk University of Technology with a BSc in computer science.

 

Advanced Course details

Modern OpenGL: Advanced Pipeline and Performance, trainer: Giuseppe D’Angelo

This training explores strategies to increase the performance of new and existing OpenGL code, with multi-pass rendering and use of uniform buffers, shader storage buffers and indirect drawing to reduce driver overhead.

Why learn about advanced pipeline and performance?

Getting the best from available hardware resources, especially on constrained systems, means deeply understanding the costs of different graphics operations, and how to optimise the rendering architecture to meet visual requirements. This course teaches how to increase performance effectively.

Target audience: Developers wanting to create or improve existing rendering code, using every technique at their disposal to understand and maximise performance, and extract the full potential from their hardware. Prerequisite: Developers already working with OpenGL, comfortable with the basics of specifying geometry, writing basic shaders and working with large image data.

About Giuseppe

An Approver of the Qt project and software engineer at KDAB, Giuseppe is a long time contributor to Qt, having used Qt and C++ since 2000. His contributions in Qt range from containers and regular expressions to GUI, Widgets and OpenGL. A free software passionate and UNIX specialist, before joining KDAB, he organized conferences on opensource around Italy. He holds a BSc in Computer Science.

 

Modern C++ – What’s New in C++17? trainer: Marc Mutz

At the end of 2017 the new C++17 standard was released, adding a sizeable amount of useful new features. All major compilers already support most (if not all) of these features.

In this training, the most useful of the new features introduced in C++17 and its predecessor will be presented. In cases for which these features depend on features introduced in C++11 or C++14, these will be refreshed as well.

New library features being presented include the new types std::any, std::optional and std::variant, the new parallel algorithms, filesystem access, std::string_view and new operations on the container classes. The new language features range from ways to improve template code with fold expressions, constexpr if, and class template deduction over improvements of lambdas to structured bindings and initalizers in if and switch statements.

Why learn what’s new in C++17?

C++ is the language that powers most applications written with Qt. To make the most out of the language, developers need to know its capabilities and pitfalls, and keep up with the incremental changes made in new releases. In this way they will learn to write easier, faster, cleaner and safer code.

Target Audience: C++ developers who want to know more about the new features introduced in C++17. Prerequisite: Knowing the basics of C++11 is a requirement, though more advanced topics will be explained as needed.

About Marc

Marc is a senior software engineer with KDAB and author of the “Effective Qt” series of articles. He originated KDAB’s “In-depth Multithreading With Qt”, C++11 and C++17 courses, and runs “-Wmarc”, a blog about Qt, C++ and Boost. The second-most prolific contributor to QtBase and former maintainer of the QtWidgets module, he has actively used the framework for more than a decade, first as a KDE contributor, and then on the job. His most recent contribution to Qt is QStringView, a revolutionary abstraction of string data from containers. Marc is a sought-after speaker at conferences on Qt and C++ topics and holds an MSc in Theoretical Physics.

 

Profiling and Debugging for Linux, trainer: Milian Wolff

This training gives an introduction to various tools, which help developers and testers in finding bugs and performance issues. This variant of the training focuses on Linux.The tools presented cover a wide range of problems, from general purpose debugging and CPU profiling to Qt specific high-level analyzers. Often, it is relatively simple to run a tool, but interpreting the results, or even just using some of the more advanced tools, requires deep technical knowledge.

The following tools will be covered:

Debugging

  • General purpose debugger: GDB
  • Record and replay, reverse debugging: RR
  • Memory error detectors: AddressSanitizer
  • Thread error detectors: ThreadSanitizer
  • Various Qt built-in features
  • GammaRay to investigate internals of Qt Applications

Static Code Analysis

  • Compilers
  • Clazy

Profiling

  • CPU: Linux perf and Hotspot
  • heap memory: heaptrack

Target audience: Developers who want to find and fix problems. Prerequisites: Knowing the basics of C++ and Qt.

The post Qt World Summit Training – Berlin 2019 appeared first on KDAB.

Qt WebAssembly faster builds

Admittedly, building Qt WebAssembly apps takes what seems like forever. Technically, it is the linking part that takes a huge amount of time, as that is where the magic happens.

You may have missed my first blog regarding faster build times for Qt WebAssembly apps:
http://qtandeverything.blogspot.com/2019/06/faster-link-time-for-qt-webassembly.html

Here is how to get set up to use this now integrated feature.

1. You need emscripten with upstream clang, which has support for transpiling directly to wasm, instead of taking the intermediary step of building javascript, then outputting wasm binary with that. Starting with version 1.39.0, upstream clang is the default. You can use "latest" to get 1.39.x or something like "sdk-upstream-1.38.43-64bit" to get an earlier version.

./emsdk install latest
./emsdk activate --embedded latest
source ./emsdk_env.sh

You can then configure and rebuild Qt with  -device-option WASM_OBJECT_FILES=1

configure -xplatform wasm-emscripten -developer-build -nomake tests -nomake examples -opensource -confirm-license -verbose -compile-examples -no-warnings-are-errors -release -device-option WASM_OBJECT_FILES=1

Then you can build your Qt app as normal using the qmake from that build, and watch the build time speed up!

*NOTE* Using  WASM_OBJECT_FILES with a multi-threaded build is still experimental, as both threads and using wasm object files in emscriptem/wasm and Qt are experimental. I have not seen any real issues regarding the use of both of these at the same time.

You can read more about Qt for WebAssembly, mobile and embedded development in the book Hands-On Mobile and Embedded Development with Qt 5

The Eight Rules of Multithreaded Qt

While the concept of multithreading may be straightforward, code with threads is responsible for some wicked bugs, which can be nearly impossible to reproduce or track down. This makes writing bullet-proof code using threads a tall order. Let’s look a little deeper into why that is.

First, you need better than average knowledge about the internals of your frameworks, language, and compiler to know how to avoid threading trouble-spots. Second, you need to know about synchronization primitives and appropriate design patterns so you can create multi-threaded code that operates correctly under all conditions. And finally you need to understand how to use debugging tools with multiple threads to be able to find those tricky to reproduce issues that are inherent in multithreading bugs.

When it comes to Qt and multithreading, it’s especially true that you need to know your framework and design patterns. Qt gives you the power to make amazing multithreaded apps – as well as shoot your foot off. We’ve honed our multi-threading expertise over the years by finding and fixing threading bugs in both the Qt framework and Qt client code. Here’s a short list of our top rules for avoiding the most common pitfalls to have your Qt apps run right the first time:

1. Never call QThread::sleep()

Although there’s an API to allow your thread to sleep, that is QThread::sleep() – if you’re calling it you should really consider an event-driven design. By changing “threads that sleep” into “threads that wait for events” (or, better all, no threads at all), you’ll save a huge amount of system resources that are otherwise wasted by idle threads. QThread::sleep() is also bad for timing since the amount of time it takes before control is returned is poorly constrained. Sleeping threads can also theoretically cause problems during application termination; foreground threads can prevent the application from terminating until they awake, while background threads may never reawaken, preventing clean finalization.

2. Never do GUI operations off the main thread

Qt’s GUI operations are not thread safe, so non-main threads cannot safely perform any GUI operation. That means no widgets, QtQuick, QPixmap, or anything that touches the window manager. There are some exceptions: GUI functions that only manipulate data but don’t touch the window manager can be called on secondary threads, things like QImage and QPainter. Be careful though, as classes like QBitmap or QPixmap actually are not safe. Check the documentation for each API: if you don’t see a note at the top of the documentation saying that the function is reentrant, it’s not safe to be called except from the main thread.

3. Don’t block the main thread

Don’t call any function that can block for an unspecified amount of time on the main thread (like QThread::wait()). Since these functions stop the main thread from running, all event processing halts and your UI freezes. If you wait long enough, the OS application manager will think your app is frozen and ask the user if they want to kill it – not cool. Both are recipes for an unfriendly app.

4. Always destroy QObjects on the thread that owns them

Qt isn’t designed to allow you to destroy a QObject from any thread that doesn’t own it. That means that before a QThread is destroyed, all QObjects that the thread owns need to be destroyed first. Failing to clean up properly can cause data integrity issues, like the ever popular memory leaks and/or crashes.

How do you ensure the correct thread is the one destroying your QObject? Either create it as an automatic variable inside the QThread’s run() method, connect QThread::finished() to QObject::deleteLater(), or delay the destruction by moving the QObject to another thread with moveToThread(). Note that once you move a QObject away from the thread that owns it, you cannot touch it any more using that thread; you must use the new thread that owns the object.

5. Don’t trust your intuition when it comes to synchronization

A very common design pattern is that one thread signals its status to a monitoring thread, usually by writing to a boolean state variable that the monitoring thread can poll. With a data structure of a single word, only one thread writing to it, and only one thread reading it, it seems like this situation wouldn’t actually require concurrency protection since the read is guaranteed to happen eventually, right? Actually, even this simple case isn’t safe.

The C++ standard says that thread synchronization is mandatory and anything outside of the specification can result in undefined behaviour. If you’re not synchronizing – even in a “simple” case – you’re asking for trouble. In fact, some serious bugs have been found in the Linux kernel, in situations exactly as described here. The best thing to do is to not overthink what is safe or not – if there are concurrent accesses to the same data from multiple threads, no matter how unlikely they are to cause problems, protect them with appropriate synchronization mechanisms.

6. Act as if QObject is non-reentrant

A reentrant function means that as long as different threads are dealing with different data, it can be safely used without synchronization. The Qt documentation indicates that QObject is reentrant, but there are many caveats to this re-entrancy:

  • Event-based classes aren’t reentrant (timers, sockets, etc.)
  • Event dispatching for a given QObject happens in the thread it has affinity with; this can cause races within Qt if you touch the object from another thread
  • All QObjects in the same parent/child tree must have the same thread affinity
  • You must delete all QObjects owned by a thread before deleting the QThread
  • You can only call moveToThread() on an object from the thread the object has affinity with

To avoid all of these special cases, it’s usually easier to just act as if QObject isn’t reentrant. In practice, this means that you should only touch a QObject on the thread that owns it. This will keep you out of all the non-obvious corner cases that can cause trouble.

7. Avoid adding slots to QThread

Because QThread objects have affinity to the original thread that created them and (perhaps unintuitively) do not have affinity to themselves, this causes issues when trying to use signals and slots on a non-main thread. Although a design where a non-main thread uses a slot can be done, since it needs to side-step a lot of non-obvious gotchas our recommendation is that you just avoid this design.

If you don’t need to override QThread:run(), then don’t subclass QThread at all; just create an instance of it and you’ll avoid problems with slots (see links at the end of this blog post for my talk for how to do this with workers).

8. Use standard library threads if it’s more natural

Finally, both the C++ standard library as well as other third party libraries have a wide array of threading classes that aren’t part of Qt – parallel algorithms, coroutines, latches, barriers, atomic smart pointers, continuations, executors, concurrent queues, distributed counters, and the like.

Qt’s multi-threading capabilities are still better in some cases: for example, Qt has thread pools while the C++ standard still does not. The good news is that the C++ classes are all compatible with Qt and can be freely incorporated into your code. In fact, unless a thread manipulates QObjects and you must use Qt threads, either C++ or Qt threading classes can be used depending on what you prefer.


If you liked this short summary, you may want to watch my full QThread talk given at QtCon or see my presentation slides on this topic. These delve much deeper into the reasons behind these rules, as well as providing code samples for the dos and don’ts.

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post The Eight Rules of Multithreaded Qt appeared first on KDAB.

Aussie firestorms

As some may know, I currently reside in Australia, which is undergoing an unprecedented bush fire season. Total burnt area is about the size of Demark, with no end in sight. Whole forests and towns are being incinerated. Millions of animals, both wild and farm are being killed and injured by the swiftly moving crown fire being whipped up by high dry winds.

There are people that need help, and people that rescue animal need help as well.
https://www.news.com.au/technology/environment/bushfire-relief-how-you-can-help-those-in-need/news-story/a0476ac3538b8c373f281ea6be204421

Some of you may have seen that I authored a book that was published by Packt this last year
Hands on Mobile and Embedded Development with Qt 5

I have decided the donate all my last quarters royalties to the WIRES Emergency Fund for Wildlife. It's not much, but I wanted to help out creatures that cannot help themselves or cannot seek out help. If there is any interest, I will donate the next quarters royalties as well.


LearnPyQt — One year in, and much more to come.

It's been a very good year.

Back in May I was looking through my collection of PyQt tutorials and videos and trying to decide what to do with them. They were pretty popular, but being hosted on multiple sites meant they lacked structure between them and were less useful than they could be. I needed somewhere to put them.

Having looked the options available for hosting tutorials and courses I couldn't find something that fit my requirements. So I committed the #1 programmer mistake of building my own. LearnPyQt.com was born, and it turned out pretty great.

Built on the Django-based Wagtail CMS it has been extended with some custom apps into a fully-fledged learning management system. But it's far from complete. Plans include adding progress tracking, certificates and some lightweight gamification. The goal here is to provide little hooks and challenges, to keep you inspired and experimenting with PyQt (and Python). The site uses a freemium model — detailed tutorials, with an upgrade to buy video courses and books for those that want them.

The availability of free tutorials is key — not everyone wants videos or books and not wanting those things shouldn't stop you learning. Even so, the upgrade is a one-off payment to keep it affordable for as many people as possible, no subscriptions here!

New Tutorials

Once the existing tutorials and videos were up and running I set about creating more. These new tutorials were modelled on the popular multithreading tutorial, taking frequently asked PyQt5 questions and pain points and tackling them in detail together with working examples. This led first to the (often dreaded) ModelView architecture which really isn't that bad and then later to bitmap graphics which unlocks the power of QPainter giving you the ability to create your own custom widgets.

Custom widgets

As the list of obvious targets dries up I'll be adding a topic-voting system on site to allow students to request and vote for their particular topics of interest, to keep me on topic with what people actually want.

New Videos

The video tutorials were where it all started, however in the past year these have fallen a little behind. This will be rectified in the coming months, with new video tutorials recorded for the advanced tutorials and updates to the existing videos following shortly after. The issue has been balancing between writing new content and recording new content, but that problem is solved now we have...

New Writers

With the long list of things to tackle I was very happy to be joined this year by a new writer — John Lim. John is a Python developer from Malaysia, who's been developing with PyQt5 for over 2 years and still remembers all the pain points getting started. His first tutorials covered embedding custom widgets from Qt Designer and basic plotting with PyQtGraph both of which were a huge success.

If you're interested in becoming a writer, you can! You get paid, and — assuming you enjoy writing about PyQt — it's a lot of fun.

New Types of Content

In addition to all the new tutorials and videos, we've been experimenting with new types of content on the site. First of all we have been working on a set of example apps and widgets which you can use for inspiration — or just plain use the code from — for your own projects. Everything on the site is open source and free to use.

Goodforbitcoin desktop image

We've also been experimenting with alternatives short-form tutorials & docs for core Qt widgets and features. The first of these by John covers adding scrollable regions with QScrollArea to your app. We'll have more of these, together with more complete documentation re-written for Python coming soon.

New Year

That's all for this year.

Almost. We're currently running a 50% discount on all courses and books with the code NEWYEAR20. Every purchase gets unlimited access to all future updates and upgrades, so this is a great way to get in ahead of all the good stuff coming down the pipeline.

The same code will give 20% off after New Year. Feel free to share it with the people you love, or wait a few days and share it with people you love slightly less.

Thanks for all your support in 2019, and here's to another great year of building GUI apps with Python!

UiWatchDog: a keepalive monitor for the GUI thread

Continuing our blog series about KDToolBox, this time we will discuss UiWatchDog, a keepalive monitor for the GUI thread.

Alive?

A fundamental rule when writing applications in event-driven UI frameworks such as Qt is: do not ever block the GUI thread!

The GUI thread is also usually called the main thread of the application — that is, the thread that runs main(). In Qt the GUI thread is somehow special, because it’s the only thread from which we can perform operations in our UI; these include creating, showing, modifying our controls; updating their contents on the screen; playing visual animations; handling keyboard and mouse events; and so on.

Doing any blocking I/O (such as disk access, networking, IPC), as well as running any computationally intensive operation from within the GUI thread is going to block it for a certain period of time.

If this period is too long, our GUI will become non-responsive, and there’s nothing more frustrating for the user to have an application that feels sluggish or worse doesn’t respond at all.

The definition of “too long” depends on the requirements we have. Of course, a few seconds is completely unacceptable — most operating systems will show that our application has frozen, and potentially will ask the user to terminate it. Below that limit, it really depends: while we could have some leeway for applications using Qt Widgets, a Qt Quick application that has animations all over the place would look terrible if those animations stutter. In other words, “too long” can be as small as a few milliseconds!

Using UiWatchDog

UiWatchDog is, by design, a header only utility to help detect when the GUI thread gets stuck. The usage is straightforward, just create an instance of it in your GUI thread and then call start():

#include "uiwatchdog.h"

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

    UiWatchdog dog;
    dog.start();

    ~~~
}

If the GUI thread ever hangs for longer than a configurable time period, UiWatchDog will print debug messages to notify you of the fact. Under the hood, UiWatchDog simply spawns a separate thread that will keep checking that the GUI thread is not blocked, by “poking” it at regular intervals.

Note that you are supposed to modify the code in order to customize what should happen in case the GUI thread gets stuck; a self-explanatory comment in the source code will tell you exactly where. On Windows you can also make UiWatchDog request a debugger to be started; on other platforms it’s necessary to have a debugger already running and to install a breakpoint in the right place.

UIWatchDog is part of KDToolBox, KDAB’s collection of miscellaneous useful C++ classes and stuff. You can download it from our GitHub repository here. Have fun!

 

About KDAB

KDAB is a consulting company offering a wide variety of expert services in Qt, C++ and 3D/OpenGL and providing training courses in:

KDAB believes that it is critical for our business to contribute to the Qt framework and C++ thinking, to keep pushing these technologies forward to ensure they remain competitive.

The post UiWatchDog: a keepalive monitor for the GUI thread appeared first on KDAB.

Grantlee version 5.2 (Alles hat ein Ende, nur die Wurst hat zwei) now available

The Grantlee community is pleased to announce the release of Grantlee version 5.2.0.

For the benefit of the uninitiated, Grantlee is a set of Qt based libraries including an advanced string template system in the style of the Django template system.

{# This is a simple template #}
{% for item in list %}
    {% if item.quantity == 0 %}
    We're out of {{ item.name }}!
    {% endif %}
{% endfor %}

Included in this release contains a major update to the script bindings used in Grantlee to provide Javascript implementations of custom features. Allan Jensen provided a port from the old QtScript bindings to new bindings based on the QtQml engine. This is a significant future-proofing of the library. Another feature which keeps pace with Qt is the ability to introspect classes decorated with Q_GADGET provided by Volker Krause. Various cleanups and bug fixes make up the rest of the release. I made some effort to modernize it as this is the last release I intend to make of Grantlee.

This release comes over 3 and a half years after the previous release, because I have difficulty coming up with new codenames for releases. Just joking of course, but I haven’t been making releases as frequently as I should have, and it is having an impact on the users of Grantlee, largely in KDE applications. To remedy that, I am submitting Grantlee for inclusion in KDE Frameworks. This will mean releases will happen monthly and in an automated fashion. There is some infrastructure to complete in order to complete that transition, so hopefully it will be done early in the new year.

Building Qt Creator plugins with GitHub Actions

Qt Creator is a cross platform, highly modular, Qt C++ application.

In order to build a Qt Creator plugin you need:
  • A C++ compiler
  • The Qt SDK
  • The Qt Creator SDK

Not many plugin developers know that Qt Creator is shipping an SDK. You don't need to compile Qt Creator in order to develop a Qt Creator plugin. Also having access to all three platforms (Windows, Linux, macOS) is not a common thing for most C++ developers.

GitHub Actions


GitHub Actions is a CI/CD infrastructure provided by GitHub which would give access to all three platforms!
GitHub is also hosting a few Qt Creator plugin repositories, so I decided to try to build the Doxygen plugin (my fork with the GitHub Actions script).

GitHub Actions currently offers the following virtual machines (runners):

How to create a Qt Creator plugin in C++, a working example explained

This article will show you all you need to know to create a Qt Creator plugin in C++.

Qt Creator is the official IDE of Qt and one of the most used by C++ developers. Creating a plugin for Qt Creator is the best way to extend its functionalities and it’s pretty easy to do as you’re going to learn here.

Before we start, you need to know that everything you will find here is based and tested on Qt 5.14 and Qt Creator 4.11, which are the latest versions at the time of writing. Things might change a bit in the future, but hopefully key concepts will stay the same.

Some theory

Before moving to something practical, it’s good to understand few concepts behind plugin design and implementation.

Plugin Structure

From a software design point of view, a Qt Creator plugin is extremely simple. In the simplest case, the only class you really need is one that implements the ExtensionSystem::IPlugin interface.

How to create a Qt Creator plugin in C++ - Qt Creator plugin UML diagram

More realistically, you probably need to handle user settings as well, hence you might also need to implement the following classes:

  • Something that stores your user settings during execution (like the class Settings).
  • An implementation the Core::IOptionsPage interface for every option page you want in the Qt Creator options dialog (Tools > Options).
  • A class extending a QWidget to populate the content of an option page.

Don’t worry if things seem a bit abstract now, they will become more clear after going trough the code later.

Plugin Lifecycle

Qt Creator plugins have a well defined lifecycle for both startup and shutdown and it’s important you know how things work before creating one.

When the application starts, all plugins are put in a loading queue according to their dependencies (i.e.: what other plugins they depend on).

After that, the first part of the initialization process can begin and for each plugin:    

  • Plugin() constructor is called following queue order
  • initialize() is called following queue order – everything that requires dependencies can be done here
  • extensionsInitialized() is called in reverse queue order – use it to access initialized dependencies
  • Core::ICore sends the signal coreAboutToOpen()

Then the Qt Creator UI is shown on screen and the second part of the inizialization process begins:

  • Core::ICore sends the signal coreOpened()
  • delayedInitialize() is called in reverse queue order and with some delay between each call – this is for non critical initialization to minimize loading time of Qt Creator
  • PluginManager sends the initializationDone() signal

At this stage every plugin should be initialized and fully operational.

A similar process happens when the application is about to close:

  • Core::ICore sends the coreAboutToClose() signal
  • aboutToShutdown() is called following queue order and what happens next depends on the value returned:
    • Return SynchronousShutdown to notify termination
    • Return AsynchronousShutdown to make Qt Creator wait until the plugin sends the signal asynchronousShutdownFinished()
  • ~Plugin() destructor is called in reverse queue order

An example Qt Creator plugin: QtC Timer

The  plugin we’re going to create here is pretty simple. It shows a message to suggest the user to take a break after using Qt Creator for a certain amount of time.

How to create a Qt Creator plugin in C++ - QtCTimer, an example plugin for Qt Creator

To make things a bit more interesting, the plugin also has a dedicated options page in the Options dialog accessible from the Tools menu of Qt Creator. The only option available is the time between 2 messages.

How to create a Qt Creator plugin in C++ - QtC Timer options dialog

Keep in mind that you don’t have to use the Options dialog for your settings. You could create a sub-menu under the Tools menu or you could handle everything in a context menu that appears only when needed. There’s no right way to do this, it’s entirely up to you and your project.

I decided to keep this plugin as simple as possible to focus on the key concepts, but it’s not hard to extend it with more complex features. For example:

  • Better time handling (consider inactivity, when the window is minimized, etc..)
  • Different messages at different times (intervals or absolute)
  • Allow to accept/cancel notification
  • Usage tracking (session length,  session times, user response, etc…)
  • Play sounds when showing a message
  • More options to handle all the new features

As you can see, even something this simple can be extended quite a lot. Your imagination is the limit.

Let’s create a Qt Creator plugin

After seeing the basic concepts and defining what we are going to create, it’s time to write some code!

Setting up

The first step to create a Qt Creator plugin is to download and to install the latest versions of Qt and Qt Creator from the Qt website. The easiest way to do that is with the online installer. You will also need to install the Qt Script package which is required to build Qt Creator (even if it’s deprecated).

The second step is cloning the repository of Qt Creator to get its source code:

$ git clone http://code.qt.io/qt-creator/qt-creator.git

Then, you want to make sure you are going to build the code of a specific release. To do that just create a branch which points to the most recent tag:

$ cd qt-creator
$ git checkout -b 4.11 v4.11.0

Finally, you want to initialize all the submodules of the repository:

$ git submodule init
$ git submodule update --recursive

Now you have all you need to build the source code and to do that just launch Qt Creator and open qtcreator.pro, which you can find in the root directory of the repository. After a bit of loading the project will be ready and you can start to build. I recommend to build it in debug and release mode using shadow builds.

Something to remember when building Qt Creator from code is that ideally you need to use the same compiler and the same version of Qt used by its developers to build the official binaries. You can find this information in the About Qt Creator dialog in the Help menu.  For example, Qt Creator 4.11 has been built on Linux using gcc 5.3.1 and Qt 5.14. Using similar compilers (like gcc 5.4) is usually fine, but changing things too much (for example Clang) is probably not going to work.

Create a Qt Creator plugin project

After launching Qt Creator, you can create a plugin using the New Project wizard.

To find the right wizard, navigate these menus in the toolbar: File > New File or Project > Projects > Library > Qt Creator Plugin

How to create a Qt Creator plugin in C++ - Dialog to create a new Qt Creator plugin

The first step in the wizard will let you choose a location for your files and a project name.

Then you select a kit to use to build the plugin, make sure to match compiler and Qt version with the ones used to build Qt Creator from code.

Finally, you can enter plugin information that will be shown in the plugin details page in Qt Creator. All fields are pretty self-explanatory.

How to create a Qt Creator plugin in C++ - plugin information wizard page

The only field that is not so obvious is “Deploy into”, which offers 2 options:

    • Local user settings – for installing your plugin in the system directory. This makes it available to every instance of Qt Creator you launch.
    • Qt Creator build – for installing your plugin only for your local build of Qt Creator (the one you use to compile the plugin).

Anyway, don’t worry too much about anything in this wizard page as you will be able to change things later.

Plugin project

After finishing the new project wizard you have a basic default project with the following files in it:

  • qtctimer.pro – qmake project file
  • qtctimerplugin.h/.cpp – plugin class files
  • qtctimer_global.h – header with macros to export symbols of your plugin. In most cases you can delete this and all the related #includes as well
  • qtctimerconstants.h – constants used by your plugin. Eventually you can delete this as well
  • QtCTimer.json.in – this stores the plugin information (and, for some reason, it’s the only file which is not all lowercase)

The next step after creating a plugin project is setting the following variables in the build environment for both Debug and Release modes:

  • QTC_SOURCE – path to the source code of Qt Creator (same for debug and release)
  • QTC_BUILD – path to the build directory of Qt Creator (this should be different for debug and release)

How to create a Qt Creator plugin in C++ - build environment of Qt Creator

Eventually at some point you will also need to add plugin dependencies. You can do that by editing the QTC_PLUGIN_DEPENDS variable in your .pro file. Simply add the name of the plugins you depend on when needed.

The default project creates a simple plugin that adds a menu to the toolbar and shows an info dialog when its entry is clicked. You can build it to test that everything is fine, but after that delete all the code inside the functions in the cpp file to start from scratch.

Plugin source code

It’s time to dive into the code of our plugin, which contains the following classes:

  • QtCTimerPlugin – the plugin class that inherits from ExtensionSystem::IPlugin
  • Settings – the class handling the options
  • OptPageMain – the options page that inherits from Core::IOptionsPage
  • OptPageMainWidget – a QWidget that defines the content of the options page

In the following paragraphs I am going to describe in detail the first 3 classes. The QWidget is not described here because it’s simple Qt code to define a basic UI.

For simplicity I have also omitted some less important parts of the code. Don’t worry about them for now, you can read and experiment with the full source code later.

The plugin class – header

First of all, you need a class that handles all the logic of the plugin and acts like mediator to connect the other ones. This class is the one that inherits from ExtensionSystem::IPlugin.

#include <extensionsystem/iplugin.h>

class QtCTimerPlugin : public ExtensionSystem::IPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QtCTimer.json")

This class is automatically created by the project wizard and you don’t need to take care of implementation details like adding the right macros. You will only need to implement its pure virtual functions like initialize() and extensionsInitialized(), but also any other virtual member you might need like aboutToShutdown().

public:
    bool initialize(const QStringList & arguments, QString * errorString) override;
    void extensionsInitialized() override;
    ShutdownFlag aboutToShutdown() override;
}

The plugin class – implementation

The first member to implement is initialize(), which does 2 things:

First, it creates the Settings object to store and handle user settings. It also create the option page that will allow the user to change such settings.

bool QtCTimerPlugin::initialize(const QStringList & arguments, QString * errorString)
{
    // -- OPTIONS PAGE --
    mSettings = new Settings;
    mSettings->Load();

    mOptionsPage = new OptPageMain(mSettings, this);
    connect(mOptionsPage, &OptPageMain::SettingsChanged, this, &QtCTimerPlugin::UpdateTimer);

When the settings change, we execute the slot UpdateTimer, which updates the timer we are about to create.

The second part of this method creates and initializes the timer that controls when to show a message on screen.

    // -- TIMING --
    mTimer = new QTimer;
    UpdateTimer();
    connect(mTimer, &QTimer::timeout, this, &QtCTimerPlugin::OnTimeout);
    mTimer->start();

    return true;
}

Every time the timeout signal is emitted, we execute the slot OnTimeout, which uses a QMessageBox to show a dialog with a message.

As we don’t really need to do anything with extensionsInitialized(), we can leave it empty.

In aboutToShutdown() we disconnect all the signals and stop the timer as we are about to exit.

ExtensionSystem::IPlugin::ShutdownFlag QtCTimerPlugin::aboutToShutdown()
{
    mTimer->stop();
    mTimer->disconnect();

    mOptionsPage->disconnect();

    return SynchronousShutdown;
}

All the objects created with new are destroyed in the destructor, but I am not going to show the code here as it’s nothing special or complicated.

The Settings class – header

This class stores the user settings during execution. It also takes care of loading and saving them.

The header file is pretty simple and it can be divided in 3 parts:

  • Setters and getters for the data (omitted here for simplicity)
  • 2 functions to load and save data
  • 2 operators to compare a pair of Settings objects
class Settings
{
public:

    // ...DATA getters and setters...

    // -- I/O --
    void Load();
    void Save();

    // -- OPERATORS --
    bool operator==(const Settings & other) const;
    bool operator!=(const Settings & other) const;
};

This is also the only class of this plugin which is not a QObject.

The Settings class – implementation

The Load() member handles only 1 option (mTimeLimit), but it shows all you need to handle any number.

The first thing you need to do when working with Qt Creator settings is to get access to a QSettings object to read/write user settings. You can do that with a single static call:

void Settings::Load()
{
    QSettings * s = Core::ICore::settings();

Now you can use the QSettings object to access your options. You do that with the function beginGroup(), which takes as parameter a QString that identifies your group of settings.

Once you are inside your group of settings you can get the value of any option by calling the value() function. This function takes a QString (OPT_TIME_LIMIT) that identifies the specific setting and a default value (DEF_TIME_LIMIT) that is returned when the wanted setting is missing. This function returns a QVariant, so you have to call the right conversion function (toInt() in this case) to get a proper value,

    s->beginGroup(GROUP);
    mTimeLimit = s->value(OPT_TIME_LIMIT, DEF_TIME_LIMIT).toInt();
    s->endGroup();
}

When you are done loading all the settings you can close the group with endGroup().

Saving is specular to loading. The only difference is that this time you call the function setValue() to store each setting. The function takes a QString (OPT_TIME_LIMIT) that identifies the specific setting and a QVariant that contains the data to save. Remember that QVariant has many implicit constructors, so unless you need to save some complex data, you can just rely on that.

void Settings::Save()
{
    QSettings * s = Core::ICore::settings();

    s->beginGroup(GROUP);
    s->setValue(OPT_TIME_LIMIT, mTimeLimit);
    s->endGroup();
}

The 2 operators (== and !=) are pretty straightforward as they only compare data members, so I will not discuss them here, but you can check their code later.

Options page – header

For every page you need in the Options dialog of Qt Creator, you need to implement a Core::IOptionsPage, which contains the meta information necessary to populate the dialog.

#include <coreplugin/dialogs/ioptionspage.h>

class OptPageMain : public Core::IOptionsPage
{
    Q_OBJECT

public:
    OptPageMain(Settings * settings, QObject * parent = nullptr);

Every option page should have access to the Settings object as that’s needed for reading and writing settings. Hence, it’s good practice to pass it to its constructor.

Then it’s necessary to override the following 3 members as they are pure virtual in the interface class.

    QWidget * widget() override;
    void apply()  override;
    void finish()  override;

Finally, it’s good to have a signal to notify the plugin class when things change.

signals:
    void SettingsChanged();
};

Options page – implementation

The class constructor sets all the meta data needed by Qt Creator to handle the page properly.

OptPageMain::OptPageMain(Settings * settings, QObject * parent)
    : IOptionsPage(parent)
    , mSettings(settings)
{
    setId("QtCTimerSettings");                              // page ID
    setDisplayName("General");                              // page label in tabs
    setCategory("QtC Timer");                               // category ID
    setDisplayCategory("QtC Timer");                        // category label in options - set once
    setCategoryIcon(Utils::Icon(":/imgs/icon_timer.png"));  // category icon - set once
}

The setId() and setDisplayName() functions define the ID and the visible name of the page, whereas the setCategory(), setDisplayCategory() and setCategoryIcon() define the ID, visible name and icon of the group of pages used by our plugin. You need to call the last 2 functions only once, and you can do that in the first page you create.

The widget() functions simply creates the widget that defines all the content of the page and returns it.

QWidget * OptPageMain::widget()
{
    if(nullptr == mWidget)
        mWidget = new OptPageMainWidget(mSettings);

    return mWidget;
}

Eventually you could create a widget only once, for example in the constructor, but usually it’s better to create it when needed and to destroy it when the dialog is closed to save memory.

The apply() method is called when the settings are accepted by the user, which is when they push the buttons “Ok” or “Apply” of the options dialog.

void OptPageMain::apply()
{
    const Settings newSettings = mWidget->GenerateSettings();

    if(newSettings != *mSettings)
    {
        *mSettings = newSettings;
        mSettings->Save();

        emit SettingsChanged();
    }
}

This member gets a new Settings object from the widget, which eventually replaces the existing one if something has changed.

Things might be more elaborated when you have to handle complex settings and the Settings object gets bigger, but in our case (and in many others) this is enough.

The finish() method is called when the options dialog is closed.

void OptPageMain::finish()
{
    delete mWidget;
    mWidget = nullptr;
}

It simply deletes the widget to save memory, as discussed before.

Resources and references

Get the source code

The full source code of this plugin is available on GitHub and released under the Unlicense license.

Remember that you will also need the source code of Qt Creator to build this example.

A more advanced plugin: SIGBUILD

In case you wanted to experiment with something more advanced you can check out my plugin SIGBUILD, available on GitHub as well.

SIGBUILD notifies you when your builds terminate and tracks their stats. It offers several types of notifications and it comes with a nice systray icon you can use to monitor your builds without even opening Qt Creator.

Support this blog

If you find this post useful you might consider to sponsor me on GitHub.

With your contribution I will be able to spend more time writing posts about Qt like this one and working on my other open source project like SIGBUILD.

Stay connected

Don’t forget to subscribe to the blog newsletter to get notified of future posts.

You can also get updates following me on GithubLinkedIn and Twitter.

The post How to create a Qt Creator plugin in C++, a working example explained appeared first on Bits of Bytes.

Qt 5.9.9 Released

We have released Qt 5.9.9 today. As a patch release Qt 5.9.9 does not add any new functionality, but provides security fixes and other improvements. We are expecting this to be the last patch release of the Qt 5.9 LTS series. 

Qt 5.14 released!

Just in time to get you into the holiday spirit, we have released Qt 5.14 today. This release, as well as next year’s Qt 5.15 LTS start paving the way towards Qt 6. While we are working on making porting to Qt 6 as smooth as possible in the future by flagging deprecated functionalities, we are also introducing some of the new  features you can enjoy now already. Have a look at some of the highlights and sign up for our webinar, where we'll have a look at those changes in detail.

Release 3.3.0: Update to Qt 5.13.2 and Qt Creator 4.10.2, Jira Tima App Demo

Felgo 3.3.0 adds support for Qt 5.13.2 and Qt Creator 4.10.2, which brings many features and improvements and fixes. On top of that, you get access to a lot of new APIs and theming options on all supported platforms. Check out a new Jira time tracker demo application, that shows how to use several of the new APIs.

Migration Hints (Android Platform)

The new Qt version 5.13.2 requires an increase of the minimum SDK version to 21. Google requires the target SDK version set to 28 for submission to the Play Store. The new versions required in the AndroidManifest.xml file of your projects are:

  • android:minSdkVersion=”21
  • android:targetSdkVersion=”28

If you are interested, you can check out the full Qt changelog of this new version in the official Qt docs.

New Jira Tima Mini Demo App

This new demo shows best practices for UI design with a shared code-base across Android, iOS and desktop. It works with dummy data based on the Jira time tracking software. It uses several of the latest APIs released with Felgo 3.3.0.

It is based on the official Jira Tima mobile app developed by Felgo.

iOS Android Desktop

New Features and APIs with Felgo 3.3.0

Improvements to Desktop Hover effects and Responsiveness

The desktop theme now features hover effects and uses the mouse pointer cursor for all input elements as well as the RippleMouseArea. You also have new styling options for the main navigation on desktop, which are listed in the “New Features” section of this release.

Improved AppTextField with New APIs

AppTextField is now based on Qt Quick Controls 2 and offers several new APIs.

With the new AppTextField::inputMode property, you can use a set of predefined input modes for different types of text fields:

import QtQuick 2.0
import Felgo 3.0

App {
  NavigationStack {
    Page {
      title: "AppTextField::inputMode"
      
      AppTextField {
        width: parent.width
        inputMode: inputModeEmail
      }
    }
  }
}

You can find details on other new properties like AppTextField::passwordVisible and AppTextField::showPasswordVisibleButton in the associated documentation.

Note: This also applies to SearchBar which uses an AppTextField internally.

The AppTextField::clickEnabled property is used for text fields without manual input. When the user selects this text field, the AppTextField::clicked signal is fired instead of setting focus to the text field. This makes sense e.g. for date input fields, where you can show a date picker when the field is selected.

import QtQuick 2.0
import Felgo 3.0

App {
  NavigationStack {
    Page {
      title: "AppTextField::clickEnabled"
      
      AppTextField {
        id: textField
        width: parent.width
        placeholderText: "Select date"
        clickEnabled: true
        onClicked: {
          nativeUtils.displayDatePicker()
        }
        
        Connections {
          target: nativeUtils
          onDatePickerFinished: {
            if(accepted) textField.text = date
          }
        }
      }
    }
  }
}

Display Options of Navigation Drawer and Sidebar Option on Desktop

You can use the new property Navigation::drawerInline to display the navigation drawer inline with the content and not as an overlay. With Navigation::drawerFixed you can also disable collapsing and expanding of the drawer, resulting in a fixed navigation sidebar. This is ideal for big tablets or desktops.
Additionally you can display the drawer in a minified sidebar version containing only icons, with Navigation::drawerMinifyEnabled.

You can add your logo to the navigation drawer now, with the Navigation::drawerLogoSource, Navigation::drawerLogoBackgroundColor and Navigation::drawerLogoHeight properties.

An AppDrawer can now be minified using AppDrawer::minifyEnabled. This will cause the drawer to appear as small sidebar with only icons displayed, while the labels are hidden.

This example lets you play around with the new display options:

import QtQuick 2.0
import Felgo 3.0

App {
  Navigation {
    id: navigation
    
    NavigationItem {
      title: "Item1"
      icon: IconType.heart
      
      NavigationStack {
        Page {
          title: "Page1"
          
          Column {
            anchors.centerIn: parent
            spacing: dp(15)
            
            Row {
              AppText {
                text: "drawerInline "
              }
              
              AppSwitch {
                checked: navigation.drawerInline
                updateChecked: false
                onToggled: navigation.drawerInline = !navigation.drawerInline
              }
            }
            
            Row {
              AppText {
                text: "drawerFixed "
              }
              
              AppSwitch {
                checked: navigation.drawerFixed
                updateChecked: false
                onToggled: navigation.drawerFixed = !navigation.drawerFixed
              }
            }
            
            Row {
              AppText {
                text: "drawerMinifyEnabled "
              }
              
              AppSwitch {
                checked: navigation.drawerMinifyEnabled
                updateChecked: false
                onToggled: navigation.drawerMinifyEnabled = !navigation.drawerMinifyEnabled
              }
            }
          }
        }
      }
    }
    NavigationItem {
      title: "Item2"
      icon: IconType.star
      
      NavigationStack {
        Page {
          title: "Page2"
        }
      }
    }
  }
}

Better Theming Support for Dialogs

The Dialog and InputDialog components now have a new material style on Android. They can also be further customized with the new ThemeDialog properties.

You can now also access the title item with Dialog::titleItem alias as well as manually set Dialog::titleDividerVisible.

import QtQuick 2.0
import Felgo 3.0

App {
  
  onInitTheme: {
    // You can add custom styles for dialogs now
    //Theme.dialog.backgroundColor = "yellow"
    dialog.open()
  }
  
  NavigationStack {
    Page {
      title: "Dialog"
    }
  }
  
  Dialog {
    id: dialog
    title: "Do you think this is awesome?"
    autoSize: true
    positiveActionLabel: "Yes"
    negativeActionLabel: "No"
    onCanceled: title = "Think again!"
    onAccepted: close()
    
    // You can use Theme.dialog.defaultContentPadding to align your
    // custom content with the rest of the dialog UI.
    AppText {
      padding: dp(Theme.dialog.defaultContentPadding)
      wrapMode: Text.WordWrap
      width: parent.width
      text: "This is a very long sentence to get some line breaks in this content!"
      // Colors and alignment are platform depending for the best appearance
      color: Theme.isIos ? Theme.colors.textColor : Theme.colors.secondaryTextColor
      horizontalAlignment: Theme.isIos ? Text.AlignHCenter : Text.AlignLeft
    }
  }
}

New TextFieldRow Component for Basic Input Forms

Use the new TextFieldRow component to construct basic input forms on pages. It displays a label based on AppText together with a text field based on AppTextField.

import QtQuick 2.0
import Felgo 3.0

App {
  NavigationStack {
    Page {
      title: "TextFieldRow"
      
      Column {
        id: column
        width: parent.width
        
        TextFieldRow {
          width: parent.width
          label: "Text"
          placeHolder: "Add some text"
        }
        
        TextFieldRow {
          id: dateRow
          width: parent.width
          label: "Date"
          placeHolder: "Select date"
          clickEnabled: true
          onClicked: {
            nativeUtils.displayDatePicker()
          }
          
          Connections {
            target: nativeUtils
            onDatePickerFinished: {
              if(accepted) dateRow.value = date
            }
          }
        }
      }
    }
  }
}

Content Padding Theming Property and Helper for Cleaner Layouts

The new Theme::contentPadding property helps you streamline your layouts easier and match your content paddings with the overall app layout.

The Page offers a new Page::contentPaddingAnchorItem item that can be used to add default padding to your page content. You can anchor to it or just use its properties like margins or width for your layouts.

import QtQuick 2.0
import Felgo 3.0

App {
  NavigationStack {
    Page {
      id: page
      title: "Page::contentPaddingAnchorItem"
      
      Column {
        id: column
        spacing: dp(Theme.contentPadding)
        anchors.fill: parent.contentPaddingAnchorItem
        
        AppText {
          width: parent.width
          text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
        }
        
        // Toggle the padding with this button
        AppButton {
          text: "Toggle padding"
          horizontalMargin: 0
          property bool toggle: true
          onClicked: {
            column.anchors.fill = toggle ? column.parent : column.parent.contentPaddingAnchorItem
            toggle = !toggle
          }
        }
      }
    }
  }
}

More Features, Improvements and Fixes

Felgo 3.3.0 includes many more features, for example:

For all relevant changes, features and fixes of recent Felgo updates, please check out the changelog.

How to Update Felgo

Test out these new features by following these steps:

  • Open the Felgo SDK Maintenance Tool in your Felgo SDK directory.
  • Choose “Update components” and finish the update process to get this release as described in the Felgo Update Guide.

Update Felgo

If you haven’t installed Felgo yet, you can do so now with the latest installer from here. Now you can explore all of the new features included in this release!

For a full list of improvements and fixes to Felgo in this update, please check out the change log!

 

 

 

More Posts Like This

Release-3-2-0-Qt-5123-EcmaScript7-QtCreator-482
Release 3.2.0: Update to Qt 5.12.3 with ECMAScript 7, Subscriptions, Image Picker and Qt Creator 4.8.2

Release 3.1.0: New Felgo Plugins Version, Unified App Configuration and FlickablePage


Android 64-Bit Support with Qt and Felgo Cloud Builds

The post Release 3.3.0: Update to Qt 5.13.2 and Qt Creator 4.10.2, Jira Tima App Demo appeared first on Felgo.

How to set up TravisCI for Qt apps

When I started GitQlient and GitQlientPlugin one of the first things I wanted was to setup a CI environment. The main reason is, of course, to have a system that checks a clean build of both projects.

The other reason, however, is that I think its a quite nice environment to deploy your build in GitHub. Locally, your system can be messed up with versions and old objects that are not cleared, etc. By doing it in this way, one is allowed to have a clean build in a really controlled environment. In addition, you can run as much versions and they are deploy independently.

How to set up TravisCI for Qt apps first appeared on My C++ & Qt blog - Cesc M..

Using Visual Studio Code for Writing Qt Applications

Software developers like tools, and in particular tools that make them more productive. So in this blog post, I am going to share with you some of the experiences some of us here at KDAB have had using Visual Studio Code for Qt development.

Preview of Visual studio code

Motivation

The first question you want to ask is probably, “Why use another editor or IDE at all if we have Qt Creator, which is a perfectly good and, in particular, Qt-specific IDE, ready at our disposal?” And, of course, that’s a very valid question to ask.

For me, the main reason is that Visual Studio Code simply does some things better than Qt Creator – and other things worse, which I’ll discuss later. Also, I am doing a lot of my development on macOS, and Qt Creator does not always have the same level of stability there as it does on Linux and Windows. I am not advocating to ditch Qt Creator altogether. My current work setup uses both in parallel.

I have configured both to auto-save and auto-reload so that I can switch seamlessly between the two. Some things I do in Qt Creator, while others I do in Visual Studio Code. When I move focus, my changes are already there (or I just need to hit the “Yes to All” button in the reload confirmation dialog) and I am getting the best of both worlds.

Visual Studio… Code?

Before I go into greater detail, I’d like to explain a bit about Visual Studio Code. Many of you are most likely familiar with Microsoft Visual Studio. If not, here’s a quick summary.

Microsoft Visual Studio is Microsoft’s big and comprehensive IDE/compiler/debugger package for C# and C++ development that has been around for many years and is available for Windows and macOS (but not for Linux). And, here’s the confusing bit: Visual Studio Code has very little to do with Microsoft Visual Studio. (Though, I would guess that they use a lot of common code under the hood.)

Visual Studio Code is an offering of its own, open source, not commercialized (for the time being at least), and based on Electron. It doesn’t use the Atom editor component though, like many other development tools built with Electron. Instead, it uses a separate editor component that is also used in Microsoft’s Azure DevOps product. This is not something you need to worry about, or even know, when working with Code, of course.

Visual Studio Code (or Code, for short) can be downloaded free of charge from here.

Extensions

One of the things you’ll quickly discover with Code is the staggering amount of extensions available. Many times, when you ask yourself, “Can Code do X?”, the answer will be: “Out-of-the-box, no, with an extension, yes, just fine.

The sheer amount of available extensions (all of them free as in beer, though some of their developers ask for a small and usually well-deserved contribution) can sometimes be confusing, especially when there are several that seem to serve the same purpose. There’s a rating system though.  Whenever I was uncertain, I quickly tried several. Many of these serve very small and well-defined purposes so you can quickly find out whether a specific extension is what you need.  All extensions can be installed without leaving Code.

In fact, for my particular purpose, Qt/C++ development using Code is not supported out of the box. Code’s heritage is ‘webby’, JavaScript-related languages such as TypeScript. Installing the C/C++ extension (developed by Microsoft themselves) gives you most of what you want, though, at least in the C++ department.

VS Code or Qt Creator?

So, this being said, what are the pros and cons of using Code over Qt Creator?

First of all, at this time, Code has no knowledge of Qt itself. It doesn’t know about signals and slots, .ui or .ts files, or QML or Qt Designer. And that alone is, of course, reason enough not to switch to Code entirely. Anything that is very Qt-specific is better done in Qt Creator. It is entirely conceivable that somebody at some point in the future will write a Qt extension for Code (who knows, maybe even a KDABian?), but at this point, to the best of my knowledge, such an extension doesn’t exist.

So, if Code doesn’t know about Qt or QML, why even use it for Qt-based development? Well, even in Qt-based projects, not every task in a programmer’s life is Qt-specific. As an example, Code’s global search-and-replace functionality is vastly superior to Qt Creator’s.

Here at KDAB, we often work with very large customer code bases, often old, often without access to the original developers, so finding our way around these is key to our work. Code lets you search for symbols in a very fine-tuned way, and also lets you replace with a lot of control (by folder, by file, by individual change, with full syntax-colored diff for every potential change etc). I often find myself switching from Creator to Code just to do a search (and sometimes a replace), and then switching back.

Managing projects

A bit of a difference in how the two work is that Qt Creator, like most IDEs, is project-based. You open one (or more) projects, and it’ll load information about all files in the project, as defined in the build file (QMake .pro file or CMake CMakeLists.txt). The advantage of this is, of course, that you can’t miss anything since everything that is built is also opened and read by Qt Creator.

Visual Studio Code, on the other hand, works folder-based. You open one folder at a time (and can combine several folders into so-called “workspaces” that are opened together), so you have a finer-grained control.  However, it is easy to miss files that are in a separate folder. As previously mentioned, the code bases we often deal with at KDAB are very large (several million LOCs are not unusual), and sometimes it’s just more convenient to only open a subset of them, since opening several hundred files can slow down the best of IDEs.

Code Completion

What about code completion? Intelligent code completion has made the lives of developers so much easier, so it’s one of the most important features in any IDE. In fact, I would say it’s a tie here. Microsoft has “donated” the reputable Intellisense code completion from the big Visual Studio product to Code, but Qt Creator’s code completion is also rather nice and convenient, and they both work similarly enough to each other that it’s not too confusing to switch between the two frequently. Setting up Intellisense can be a bit of a hassle sometimes, especially when using CLang, but there is good documentation to help with that.

VCS Integration

Another advantage of Code is its very extensive support for version control systems (which these days, let’s face it, essentially means git). Qt Creator does have comprehensive git support, but I don’t find it very accessible. In particular, it is not very integrated with the actual act of writing code.

With Code, I can get small annotations about who changed a line of code and when, in a subdued color. These are easy to ignore when you don’t need them, but available right away when you do; this is much more efficient that running git log or git blame separately (this particular feature comes by way of the GitLens extension). Even other developer tools are nicely integrated; for example, if your organization is using Atlassian’s Jira issue tracking system, as we do here at KDAB, there is a convenient and comprehensive extension for that.

CMake

Finally, a few words about CMake. With the recent decision to make CMake the default build tool for Qt-based projects, this will likely change, but at this time, CMake is not really a first-class citizen in Qt Creator, which was built very much around QMake.

You certainly can use Qt Creator’s nice scaffolding for new projects and tell it to use CMake, but if you add new files or classes, you’ll need to add them manually to your CMakeLists.txt Code by way of the CMake extension, which gives you a lot more support here, at least for the time being. It remains to be seen how much CMake support there’ll be in Qt Creator once Qt 6 is released.

Summary

In summary, we would advise Qt developers who care about their productivity to give Visual Studio Code a try. It won’t replace Qt Creator in the foreseeable future (maybe never), but it certainly is yet another tool in the shed that helps you write more and better code in less time.

Editorial note (28 Nov 2019)

A previous version of this post had some incorrect information regarding the support for multiple programming languages in VS Code and Qt Creator. We have removed such incorrect information to avoid spreading it further. We apologize for the mistake.

The post Using Visual Studio Code for Writing Qt Applications appeared first on KDAB.