Style resource
First off, let’s create a new resource file to contain the non-QML visual elements we will need. In the cm-ui project, Add New... > Qt > Qt Resource File:
Name the file assets.qrc and place it in cm/cm-ui. Your new file will automatically open in the Resource Editor, which I don’t find to be a particularly helpful editor, so close it. You will see that the assets.qrc file has been added to the Resources section of the cm-ui project. Right-click on it and select Add New… > Qt > QML File. Call the file Style.qml and save it to cm/cm-ui/assets.
Edit the assets.qrc file in the Plain Text Editor in the same way we did for the views:
<RCC> <qresource prefix="/assets"> <file alias="Style.qml">assets/Style.qml</file> </qresource> </RCC>
Now, edit Style.qml and we’ll add a single style property to use for the background color of our views:
pragma Singleton import QtQuick 2.9
Item { readonly property color colourBackground: "#f4c842" }
What we are doing here in C++ terms is creating a singleton class with a public member variable of type const color called colourBackground with an initialized value of a hex RGB code for (very) light grey.
Now, we need to perform a little bit of a manual fudge to wire this up. We need to create a Module Definition file named qmldir (with no file extension) in the same folder as Style.qml (cm/cm-ui/assets). There is no built-in template for this type of file, so we need to create it ourselves. File Explorer in older versions of Windows used to make this a painful exercise as it always insisted on a file extension. A console command was required to forcibly rename the file. Windows 10 will happily create the file without an extension. In the Unix world, files without an extension are more common.
With the qmldir file created, edit assets.qrc and insert a new entry for it right next to Style.qml inside the /assets prefix:
<file alias="qmldir">assets/qmldir</file>
Double-click on the newly added qmldir file and enter the following lines:
module assets singleton Style 1.0 Style.qml
We have already seen modules when we import QtQuick 2.9. This makes version 2.9 of the QtQuick module available for use in our views. In our qmldir file, we are defining a new module of our own called assets and telling Qt that there is a Style object within version 1.0 of that module, for which the implementation is in our Style.qml file.
With our new style module created and wired up, let’s now put that modern off-white color to use. Start with the first child view we see, SplashView, and add the following to get access to our new module:
import assets 1.0
You’ll note that we’re presented with an angry red underline, suggesting that all is not well. Hover over the line with the mouse pointer, and a tooltip will tell us that we need to add the import path to our new qmldir definition file.
There are a couple of ways to do this. The first option is to go to the Projects mode and select the current kit’s Build settings and then Debug mode. At the bottom in the Build Environment section, click on Details. Here, you can see a list of all the environment variables for the current kit and configuration. Add a new variable called QML2_IMPORT_PATH and set its value to the cm-ui folder:
This adds the project working directory of the cm-ui project (/projects/qt/cm/cm-ui) to the QML Import Path. Note that our module name must reflect the relative path to the qmldir file from this import path.
The problem with this approach is that this environment variable is tied to the cm.pro.user file. If you share the project with other developers, they will have their own cm.pro.user files, and they will have to remember to add this variable too. Furthermore, it's tied to an absolute path and if you copy the project code to another machine, it may not be at that location.
The second, and preferred, option is to add the following line to main.cpp immediately after instantiating QQmlApplicationEngine:
engine.addImportPath("qrc:/");
So why qrc:/ and not the absolute path to our qmldir file? You'll remember that we added our views.qrc resource bundle to a RESOURCES variable in cm-ui.pro. What this does is it takes all the files from views.qrc and compiles them into the application binary in a kind of virtual filesystem, where the prefixes act as virtual folders. The root of this virtual filesystem is referenced as qrc:/ and by using this in the import path, we are essentially asking Qt to look inside all of our bundled resource files for any modules. Head over to cm-ui.pro and ensure that our new assets.qrc has also been added to RESOURCES:
RESOURCES += views.qrc assets.qrc
This can be a bit confusing, so to reiterate, we have added the following folder to search for new modules, either using the QML2_IMPORT_PATH environment variable to search our cm-ui project folder on our local physical filesystem, or the addImportPath() method to search the root of our virtual resource filesystem at runtime.
In both cases, our qmldir file that defines our new module is in a folder called assets a level below that, that is, either <Qt Projects>/cm/cm-ui/assets in the physical filesystem or qrc:/assets in the virtual.
This gives us the module name assets. If our folder structure was deeper, like stuff/badgers/assets, then our module would need to be called stuff.badgers.assets, as that is the path relative to our defined import path. Similarly, if we wanted to add another module for our existing views, we would create a qmldir file in cm-ui/views and call the module views.
With all this in place, we can now use our new module. Including the module means we can now access our singleton Style object and read properties from it. Replace the color property of our SplashView:
Rectangle {
... color: Style.colourBackground
... }
Repeat this to set the background color for all of our views except MasterView. Remember to include ui.assets 1.0 in each view too.
When you build and run the application, you may wonder why we’ve gone through all of that rigmarole when the views look exactly the same as they did before. Well, let’s say that we’ve just had a meeting with the guys from marketing where they told us that yellowy orange is not a good fit for the brand any more, and we need to change all the views to be a clean off-white color. We would previously have had to go into every view and change the color from #f4c842 to #efefef. Now, there are only seven of them, so it’s not a big deal, but imagine if we had to change all the colors for all the components in 50 complex views; that would be a very painful exercise.
However, go to Style.qml and change the colourBackground property from #f4c842 to #efefef. Build and run the application and bask in the glory of our rebranded app! By setting up our shared style component early, we can add the properties as we go and then restyling our app later becomes much easier. We can add properties of all types here, not just colors, so we’ll be adding sizes, fonts, and other things as we progress further through our development.