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.
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