ImaginativeThinking.ca


A developers blog

How to resolve Component naming conflicts in QML

By: Brad

Hey Brad, I’ve been using Qt Quick for a bit now and have created a whole bunch of custom controls. I recently upgraded to the latest version of Qt and now I’m running into issues because Qt added a bunch of new Qt Quick Controls and a few of them use the same name as my custom controls. How do I resolve these naming conflicts?

I ran into this very same issue my self not to long ago and I’ve got good news for you, there is a way to deal with naming conflicts that doesn’t require you to go and rename all your components.

In this tutorial I’ll show you how to resolve QML Component Naming Conflicts.

conflict

Per the above lets say you defined your own QML component that represents a custom button that has a nice red colour. This custom button of yours exists in a file called Button.qml so that when you import it you can use it simply by declaring Button{...}. Now lets say you are working on an interface that will use your button and a drop down control. Instead of creating your own drop down your going to import and use the one that comes with Qt in the Qt Quick Controls module. As soon as you import the Qt Quick Controls module your nice red button turns into a drab standard grey one. What the heck just happened!!??

The Qt Quick Controls module also has a button control which share the same name as your custom button component (Button); the QML engine can not import two components with the same name into the same namespace.

When the QML engine processes a QML script it reads it line by line going from top to bottom. If your script imports your button first then imports the Qt Quick Controls module the engine will first register your component with the name Button then it will register the Qt Quick Controls button component with the name Button effectively un-registering your component.

import "redButton" // the dir where Button.qml exists
import QtQuick.Controls 1.1 

//Would be the Qt Quick Control button not yours.
Button { 
    id: redButton
}

So How can I make sure my Button component is used?

Well the simple answer would be to change the order of your import statement so that the registration of your button component comes after the Qt Quick Controls import but that seems a little fragile. The next programmer that comes along and imports something new or imposes a style standard (i.e. import framework modules first) would break things pretty quickly.

The Intended Solution

The good news is that Qt didn’t leave you high and dry they have a built in mechanism to deal with naming conflicts.

When you import modules in your QML script all the components in the module are imported into a non-qualified local namespace. Think of the import statement as something similar to a combination of the #include<> and using statements in C++. In C++ you deal with naming conflicts by putting your classes into different qualified namespaces; when you include a class you need to access the class by qualifying which namespace your intending to use. Of course typing std::string over and over again is a pain so C++ also has a using statement where you can tell the compiler that within this file scope put all the classes into a local non-qualified namespace so that when you see string know to use std::string. Its a nicety to save typing and where C++ made that an opt-in nicety QML made it an opt-out. The import statement in QML by default puts all the imported components into a non-qualified local namespace so that you can access any of the components within the module without qualification.

Most of the time this work without issues and lets you write your QML script with far less typing but in the above case its landed us in a naming conflict problem. To resolve this you can tell the import statement to place the components into a qualified local namespace instead by using the as keyword.

import "redButton" as RedButton

By adding the as keyword and a qualification name to your script you can now explicitly state which button component you intend to use.

import "redButton" as RedButton // the dir where Button.qml exists
import QtQuick.Controls 1.1 

RedButton.Button {
    id: redButton
}

So there you go that is how you can resolve naming conflicts between QML components. Note the same solution can be used if the conflicting components are C++ in origin instead of QML. Naming Conflict Sample 2 illustrates this point, also see How to resolve C++ Component naming conflicts in QML to learn more.

You can download a sample application which illustrate the above here:
Naming Conflict Sample 1: QML Component Conflicts
Naming Conflict Sample 2: C++ Component Conflicts

Here is where you can find the official Qt documentation on the import statement

Thank you I hope you have enjoyed and found this tutorial helpful. Feel free to leave any comments or questions you might have below and I’ll try to answer them as time permits.

Until next time think imaginatively and design creatively

Brad

My interest in computer programming started back in high school and Software Development has remained a hobby of mine ever since. I graduated as a Computer Engineering Technologist and have been working as a Software Developer for many years. I believe that software is crafted; understanding that how it is done is as important as getting it done. I enjoy the aesthetics in crafting elegant solutions to complex problems and revel in the knowledge that my code is maintainable and thus, will have longevity. I hold the designation Certified Technician (C.Tech.) with the Ontario Association of Computer Engineering Technicians and Technologists (OACETT), have been certified as a Professional Scrum Master level 1 (PSM I) and as a Professional Scrum Developer level 1 (PSD I) by Scrum.org as well as designated as an Officially Certified Qt Developer by the Qt Company. For more on my story check out the about page here

Feel free to write a reply or comment.