37

I want to declare a global property in a config file and use it in other files. for example declare mainbg in:

Style.qml:

property color mainbg: 'red'

and use it in other QML files (like view.qml and main.qml). How can I do this work?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Vahid Kharazi
  • 5,723
  • 17
  • 60
  • 103

7 Answers7

53

Use a QML Singleton.

Please reference "Approach 2" on this page -- The ugly QTBUG-34418 comments are mine.

These are the pieces you need:

Style.qml

pragma Singleton
import QtQuick 2.0
QtObject {
    property color mainbg: 'red'
}

qmldir

This file must be in the same folder as the singleton .qml file (Style.qml in our example) or you must give a relative path to it. qmldir may also need to be included by the .qrc resource file. More information about qmldir files can be found here.

# qmldir
singleton Style Style.qml

How to Reference

import QtQuick 2.0
import "."  // this is needed when referencing singleton object from same folder
Rectangle {
    color: Style.mainbg  // <- there it is!!!
    width: 240; height 160
}

This approach is available since Qt5.0. You need a folder import statement even if referencing the QML singleton in the same folder. If is the same folder, use: import "." This is the bug that I documented on the qt-project page (see QTBUG-34418, singletons require explicit import to load qmldir file).

pixelgrease
  • 1,940
  • 23
  • 26
  • 1
    Why not just a simple `.pragma library` javascript file? – Matteo Feb 22 '18 at 16:15
  • 1
    As [tonytony](https://stackoverflow.com/users/1096537/tonytony) answered, `.pragma library` does not guarantee a shared instance. A singleton lets you change a global style on-the-fly with all bindings updating to show the same font, color, etc. – pixelgrease Oct 28 '20 at 00:57
  • After few years I blindly suggest a Q_PROPERTY in a dedicated style class rather than abusing the QML layer for this kind of needs, it is way more reliable – Matteo Oct 29 '20 at 11:20
28

Basically, if you don't need property binding (if you value is a constant and will not need to be notifiable on change) you can define it in a Javascript shared library, like this :

// MyConstants.js
.pragma library
var mainbg = "red";

And use it in QML like this :

import "MyConstants.js" as Constants

Rectangle {
     color: Constants.mainbg;
}

But the bad side of this are : - no strong typing (JS doesn't really know about types) so you could put anything even if it is not a color. - and if you change mainbg, the Item using it won't be notified about the change and will keep the old value

So if you need type checking and binding/change notify, simply declare your property as a member of the root object in you main.qml, and it will be accessible from everywhere in the QML application, because the property will in fact be directly registered into the Qml Context object, which is global by definition.

Hope it helps.

TheBootroo
  • 7,408
  • 2
  • 31
  • 43
22

You can create a js file and import it to all of the files that have to use this property.

js file:

//Note: you only need '.pragma library' if you are planning to
//change this variable from multiple qml files
.pragma library
var globalVariable = 20;

qml file:

import "test.js" as Global

Rectangle {
  id: main
  width: 300; height: 400

  Component.onCompleted: {
    console.log( Global.globalVariable)
    //you can also change it
    Global.globalVariable = 5
  }
}
JuliusG
  • 2,321
  • 21
  • 30
  • 2
    don't forget to put `#pragma library` in there. – user1095108 Mar 07 '13 at 07:43
  • 6
    I must notice that `.pragma library` _allowes_ JS file to be used by several QML files, but _does not guarantee_ that there will be only one instance of the library. I've just encountered severe bug in my application that is due to my attempt of using JS library as global state container. – tonytony Aug 12 '15 at 11:43
9

Adding some contribute to @pixelgrease answer, I found another technique that doesn't require the path relative import ".", workarounding the bug QTBUG-34418. This is useful especially if one has qmldir and singleton class in a different place than the qml file where the singleton is used. The technique requires defining a proper module inside the tree structure: the module is then resolved by adding the parent path of the module to the QML engine with QmlEngine::addImportPath(moduleParentPath). For example:

qml/
├── <ModuleName>/
│ ├── <ClassName>.qml
│ ├── qmldir

In main.cpp you have then:

QQmlApplicationEngine engine;
engine.addImportPath("qrc:/qml");    // Can be any directory
engine.load("qrc:/qml/main.qml");

If you use resources, qml.qrc:

<RCC>
 <qresource prefix="/">
      (...)
 <file>qml/main.qml</file>
 <file>qml/MySingletons/MySingleton.qml</file>
 <file>qml/MySingletons/qmldir</file>
 </qresource>
</RCC>

In qmldir:

module MySingletons
singleton MySingleton 1.0 MySingleton.qml

In main.qml, or any other qml file in a different directory:

import MySingletons 1.0

Then you use MySingleton class as usual. I attached the example MySingletonWithModule.7z to bug QTBUG-34418 for reference.

ceztko
  • 14,736
  • 5
  • 58
  • 73
3

Add this property in main and you can access it in any qml,this may not be the correct way but this works.

or if you want to group the property add them in a qml include that qml in main and give an id,now you can access this property using that id

main.qml

 Item{
 width:10
 height:10

 Model{
 id:globdldata
 }



 }

Model.qml

Item {

property color mainbg: 'red'

}

you can use globdldata.mainbg anywhere

Bibin
  • 433
  • 5
  • 12
1

You can always create a new QML object file that contains the properties that you want shared across qml files. Just import it the same way you would any QML object and you have access to properties. Now, if you want to be able to modify these properties and have the changes shared across instances things get a lot trickier and you will most likely want to resort to some sort of solution using the .pragma library js files. Unless you want to write some sort of C++ alternative.

Deadron
  • 5,135
  • 1
  • 16
  • 27
1

Starting from Qt 6.2 with CMake, there is property QT_QML_SINGLETON_TYPE, which allows easily use QML singletons without any import and qmldir.

If you have Style.qml

pragma Singleton
import QtQuick 2.0

QtObject {
    property color mainbg: 'red'
}

Set this extra property in CMakeList.txt

set_source_files_properties(Style.qml PROPERTIES
    QT_QML_SINGLETON_TYPE TRUE
)

Use in other files

Rectangle {
    color: Style.mainbg
}
Janis Coders
  • 157
  • 1
  • 6