Qt Training -- Phil's Self Study Report -- Feb/Mar 2014
Initial draft: 3-7-2014. Minor edits: 3-9-2014.

This document has the following major sections:

  1. Summary of what I covered in this training.
  2. Summary of new features in Qt and C++ that we may wish to take advantage of in the future.
  3. How much effort it would take to adopt new version or new features; scope of effort.

(1) Summary of what I covered in this training.

I studied the following areas, viewing conference lecture and webinar video presentations, reviewing related Qt and C++11 documentation, and worked through a QML tutorial.

  1. QML/Qt Quick and QML/C++ integration (large topic)
  2. Best Practices for Qt Widget-Based Programming.
  3. Qt Webkit and HTML5 integration.
  4. Qt5 (beyond just QML) and C++11 features.
  5. Internationalization.

Preparation included:

  1. Compiling a list of relevant training materials.
       See: http://cadswes2.colorado.edu/~philw/2014/QtTraining/Resources.html
  2. Creating a study plan (which initially focused on just the first item above).
       See: http://cadswes2.colorado.edu/~philw/2014/QtTraining/StudyPlanOne.html
  3. Built the Qt Creator IDE. This was used by most presentations on QML/Qt Quick, and in the QML tutorial I worked through. I initially attempted to build Qt 5.2.1, which includes Qt Creator 3 for Qt Quick 2, but ran into difficulties. But I was able to build Qt Creator 2.8.1 on my 32-bit Windows XP machine using Qt 4.8, so I used that. (That general version is actually what was used in the QML tutorial and most of the video presentations).

These are the materials I watched and studied:

Qt DevDays 2011 / Programming with Qt Quick. This is a 5.5-hour course:
http://qt-project.org/videos/watch/programming-with-qt-quick-1-5-meet-qt-quick ...

(2) Summary of new features in Qt and C++ that we may wish to take advantage of in the future.

(2A) QML / Qt Quick

Background Discussion:

Most of my study was of QML and Qt Quick (the overall QML development and execution framework). The motivation and focus of this technology is not fundamentally about solving problems inherent in developing large desktop applications. It will become important to us in the future primarily because "widget" development in Qt has ended (the Qt5 Qt Widgets module is in the "done" state; no significant new functionality is anticipated), and QML is the user interface technology now being developed.

QML / Qt Quick is a low-level user interface technology with a few high-level features relevant to mobile and other touch devices, such as visual controls which "shake" when operated. The emphasis is on creating "novel" and unique user interface experiences. There are however efforts to create "Qt Quick Components" libraries -- sets of standard widget-like QML controls. In particular "Desktop Components" may be interesting when it is more fleshed-out. The "components" emphasis now is for mobile and other embedded applications.

QML makes certain aspects of designing and laying out a user interface pretty easy. The idea is that QML-defined user interfaces could be produced by non-IT professionals and handed off to developers to implement. Most required signal/slot connections are created implicitly, under the covers; changes to "properties" are automatically propagated to entities which depend on those properties. But QML might not scale very well to large complex dialogs (though since there is so much attention on QML now, such difficulties may be addressed). For example, if a "tab order" is explicitly defined, each and every element has to specify backward and forward references to the prior/subsequent item in the tab order; that seems very cumbersome and fragile. (Currently, with Qt widgets, initially defining the tab order in Designer, and subsequently modifying it by directly editing the tab order widget list in the UI file works very well).

The paradigms and technologies used by QML where picked, I would say, by "coolness" of these things. There is a lot of excitement in new language and framework technologies involving: (1) Declarative syntax, (2) JavaScript for functionality, and (3) languages based on the JVM (Java Virtual Machine). Only the first two of these apply to QML, but two out of three is sufficiently sexy. The disadvantage of especially the use of an interpreted language (JavaScript) is that much of the complexity and "best practices" conventions are dedicated to rather dire performance considerations -- i.e. instead of saving the complexity for "domain" issues. This implementation-centric complexity isn't necessarily worse than the level of user-interface implementation complexity inherent in development with traditional Qt4 widgets, but my point is that I don't think it got better with QML where we really needed it -- e.g. true model/view implemented complex tables and lists with great performance (even with HUGE data sets) and more high level features (e.g. fixed, i.e. non-scrolled special columns and rows). (In Qt 4.8, QHeaderView row and column geometry computations don't perform well with large data sets; not truly model/view).

With that said, some foreseeable possible uses of QML in RiverWare and RiverSMART are:

  1. Novel "context menu" popup dialogs, especially as a replacement for three-or-more levels of submenus.
  2. Use of independently implemented general purpose QML components, e.g. for data visualization. (I haven't identified any specific examples of this. This is just a possibility).

In addition to that, there is value in our development staff learning and using JavaScript, as that is used for interfacing to other related (esp. HTML5-centric) user interface and internet technologies.

I recommend that we first move to Qt 5 (i.e. Qt 5.2 or later) before attempting to use QML / Qt Quick in RiverWare. Qt 4.8 uses an early version of these technologies. These have changed and been improved in some significant ways in Qt 5. The latest significant improvement is in Qt 5.3 (expected to be released at the end of April, 2014): QQuickWidget for easier QML / C++ Qt Widget interoperability.

I did ask a question about QML on the "Qt Interest" mailing list, and received one response:
[Interest] QML/declarative languages and E-Prime?

Does anyone know how the declarative nature of QML can be described in E-Prime? (English without the verb, "to be")  ...  http://en.wikipedia.org/wiki/E-Prime


"Nothing to declare!" Well, "to be or not to be" is a similar question, too...
;) Happy week-end, all!
Oliver

(2.2) Best Practices for Qt Widget-Based Programming.

We are already doing a lot of what was covered in the material. Some things which I had overlooked in my Qt development include:

One overview of often-missed Qt functionality discussed these Qt classes:

One particular performance enhancement recommendation which I'm not excited about is "minimizing QPainter state changes". (An analogous recommendation was made also for custom drawing using QML). It's apparently expensive to change a QPainter's QPen and QBrush during a graphical item's paint event. So the suggestion is to restructure the code such that, for example, the backgrounds of all objects are painted at once, and then other similar features of all objects are painted in separate passes. This requires _not_ defining individual graphics items for application-level items (e.g. RiverWare simulation objections), sacrificing coherence between the application data model structure with the graphical implementation. We are well into the 21st century. Performance shouldn't be the primary organizing principle in our code structure unless we are handling data a few orders of magnitude larger than what we are dealing with in RiverWare (e.g. seismic data).

(2.3) Qt Webkit and HTML5 integration

We've already starting using QtWebKit in some advanced ways, e.g. Patrick's implementation of model reports. That's the right idea. A lot of new HTML5 feature work available in Qt5 focuses on performance issues, e.g. the much faster "Google Chrome" V8 JavaScript engine.

(2.4) Qt5 (beyond just QML) and C++11 features.

The significance of both moving to Qt5 and to Visual Studio 2012 (a more complete and up-to-date implementation of C++11) -- as separate considerations -- is really just "incremental", I think. There isn't any one particular aspect of either of these which would provide profound benefits to RiverWare or RiverSMART in the short term. Moving forward with these has the benefits of:

  1. Being in a position to interface to a broader range of external software products, e.g. for data visualization.
  2. Realizing performance benefits made possible by new C++11 features (such as new "move semantics" and explicit "RValue" expressions). The latest versions of Qt5 have changes (e.g. in QString and Qt collection classes) which realize these performance benefits. I believe Visual Studio 2010 (our current IDE/compiler) is sufficient for most of these optimizations.

We could potentially make changes in RiverWare to directly make use of these C++11 performance provisions -- either just provisionally, e.g. in the SeriesSlot assignStdValue path, or callback mechanisms -- or after doing some profiling. This would involve making very specific changes at key places in code to utilize "move" constructors and assignment operators, and explicit "RValue" semantics.

One particular language feature I believe we should make use of (in C++11, available in VS 2010) is "override" on virtual method declarations in subclasses. This fixes a C++ language mistake where a mismatch in a virtual method's name or parameters quietly prevents it from actually overriding the base class method (so that it just doesn't get called). Aside from the fact that such errors would be caught by the compiler, its presence in source code (in .hpp files) documents the fact that the code is correct in that respect.

Other C++11 features which will improve the quality of our source code are:

One caution. There may be reason to make more of our constructors "explicit" -- even for constructors which take more than one argument.

When building Qt we may need to add this symbol to enable use of certain C++11 features:

QMAKE_CXXFLAGS += -std=c++0x
(.. or c++11, would be more current, and should work with VS 2012; "C++11" was originally called "C++0x").

Here is an extensive C++11 article (FAQ) by Bjarne Strousup:

C++11 - the new ISO C++ standard
http://www.stroustrup.com/C++11FAQ.html

(2.5) Internationalization

Providing RiverWare and RiverSMART in other languages would of course be a huge initial effort and would forever add a lot of new overhead to future development. Our source code would be significantly burdened with translation instrumentation -- more than just wrapping literal strings in "tr()", as we will find that more context information needs to be provided to translators.

We would need to define and document required coding standards for displayed text strings vis-a-vis translation provisions.

Currently, our software team does generally apply "tr()" to literal strings when they appear within Q_OBJECT classes. Outside of Q_OBJECT classes, note that use of the QT_TR_NOOP macro is not sufficient -- that's only a flag for Qt Linguist. Use of a non-QObject-context form of tr() is still needed to provide the run-time replacement with translated content.

I'm pretty sure that the old "languageChange" methods generated from Qt3 uic (if I'm understanding correctly) are no longer relevant. (There are a lot of those left over in our source code). In Qt4, actually, dynamic language changing requires quite a bit of extra work. The simplest thing is to start the application up with a particular language setting (possibly referring to the locale), and not subsequently change it during the session.

We may want to disable automatic casts from char* to QString, so that string literals needing translation won't be missed. This is done by adding this project file directive:

DEFINES += QT_NO_CAST_FROM_ASCII

The compiled binary ".qm" files generated from Qt Linguist can be bound to the application as Qt Resource Files (i.e. compiled into the executable). That's an alternative to distributing separate ".qm" files with the RiverWare executable.

I understand that it IS possible to "merge .ts files" (apparently a feature of the "lupdate" utility) -- so that the translation effort would not have to start from scratch for each release. There are naive uses of the 2nd tr() parameter (const char* disambiguation) which should be avoided, as changes in that informational comment text will cause unnecessary loss of prior translation work. There is a preferred way to provide a context message to the translator using a special form of comment in the line above the statement containing a string literal. (All of this additional instrumentation and translation commenting will certainly interfere with the readability of our source code).

(3) My recommendation for what we should do in the coming year; scope of effort.

A couple weeks ago, I had mentioned that I was leaning towards recommending upgrading the compiler (from Visual Studio 2010 to Visual Studio 2012) before porting to Qt5. I'm reversing that recommendation. Visual Studio 2010 has the important provisions needed to realize some of the performance optimizations in Qt5. I have not yet succeeded in building Qt 5.2.1 with Visual Studio 2010, but it can be done. [Update 3-8-2014: I have succeeded in doing this at home].

I do recommend upgrading RiverWare and RiverSMART from Qt 4.8.5 to Qt 5.2 (or maybe wait for Qt 5.3) soon if we can. The immediate benefits would essentially be:

  1. Being better positioned for integration with external tools, e.g. for HTML5 interoperability or for data visualization.
  2. Being better positioned for making limited use of QML for special purposes (e.g. special context-menu provisions).
  3. "Free" performance improvements.

With a small amount of conditional compilation, all source code changes for the port can be merged back into our Qt 4.8 builds. There won't be any time when ongoing development needs to stop in order to complete any part of this porting work. Of course, we won't have Qt5 executables until the porting is complete, but in the mean time all development work and porting work can be freely merged in either direction.

It's difficult to come up with an accurate estimate without any experience doing this sort of port. After the first two steps below, followed by a very limited amount of porting (e.g. a week or two) I think a ballpark estimate would be possible. My sense is that the RiverWare port will be doable within one or two months.

The basic steps are:

  1. Built Qt5 (e.g. Qt 5.2.1 or Qt 5.3.0) for 64-bit windows, both Debug and Release. (Note: By default, and recommendation, QWebKit is unconditionally built for Release -- it is huge). (32-bit Qt5 builds should be postponed until the end of this porting work, with the latest available Qt5 version).
  2. Devise Qt5 Project (.pro) files for RiverWare. We should probably use a more conventional approach than what we are currently doing with Qt4. I understand that distinct source and "generated" source projects may not be necessary.
  3. Start Qt4-to-Qt5 porting a few representative RiverWare libraries.

--- (end) ---