Home > Mobile >  QML singletone style nested files
QML singletone style nested files

Time:01-03

I've got a defined style for the QML application as a separate file MyStyle.qml:

pragma Singleton
import QtQuick 2.15
import QtQml 2.15

QtObject {
    property color color1: "#ffffff"
    ...
}

I want to modify it with another file for ultra resolution >2k MyStyle_2k.qml.

MyStyle{
    color1: "#000000"
    ... 
}

The style is registered in main.cpp:

QScreen* screen = QGuiApplication::primaryScreen();
auto screenHeight = screen->geometry().height();

QUrl styleUrl;

if(screenHeight > 1440){
    styleUrl = QUrl("qrc:/gui/style/MyStyle_2k.qml");
}else{
    styleUrl = QUrl("qrc:/gui/style/MyStyle.qml");
}

qmlRegisterSingletonType(styleUrl, "MyStyle", 1, 0, "MyStyle");

Unfortunately, it doesn't work because of errors:

QQmlApplicationEngine failed to load component qrc:/path/other_file.qml: Type MyStyle/MyStyle unavailable :9:1: Composite Singleton Type MyStyle is not creatable.

Is it possible to modify qml singleton by another file?

CodePudding user response:

You are trying to create an instance of a singleton type which is not possible hence the error message. If you want to create an instance of the style and modify it inside QML you need to use qmlRegisterType().

Or you need to write MyStyle.color1: "#000000" to modify the singleton value.

CodePudding user response:

You should name both of your files MyStyle.qml but organize them in the following way:

qrc:/gui/style/MyStyle.qml
qrc:/gui/style/ highres/MyStyle.qml

Then, you can let Qt know which version of MyStyle.qml to load via the use of file selectors. Note the usage of the plus sign as a prefix to highres. This is how Qt organizes file overrides based on default or custom file selectors. The easiest way to declare highres as a custom file selector is via QT_FILE_SELECTOR environment variable, e.g.

QScreen* screen = QGuiApplication::primaryScreen();
auto screenHeight = screen->geometry().height();
if (screenHeight > 1440) {
   qputenv("QT_FILE_SELECTOR", QString("highres").toUtf8());
}

This code needs to happen very early on in your main.cpp because QT_FILE_SELECTOR will be checked once and will not be rechecked later on.

From https://doc.qt.io/qt-6/qfileselector.html:

Further selectors will be added from the QT_FILE_SELECTORS environment variable, which when set should be a set of comma separated selectors. Note that this variable will only be read once; selectors may not update if the variable changes while the application is running. The initial set of selectors are evaluated only once, on first use.

If you do not wish to use QT_FILE_SELECTOR environment variable, then, the proper way to define a file selector for QML use is via QQmlFileSelector:

QScreen* screen = QGuiApplication::primaryScreen();
auto screenHeight = screen->geometry().height();
QQmlFileSelector* selector = null;
if (screenHeight > 1440) {
   selector = new QQmlFileSelector(&engine);
   selector->setExtraSelectors(QStringList() << QString("highres"));
}

The advantage of using QQmlFileSelector is you can control the file selectors that are active in runtime. i.e. you can add/remove a file selector. However, this also means that every time you change a file selector, you have to force components that are already loaded to reload. However, it comes at the cost of additional coding requirements, in that, you need to instantiate the QQmlFileSelector configure it, force a reload of components (which is even harder to do for singletons), and clean up code when your program exits (note I have not provided any of this, since, it is left up to you how to instantiate and release QQmlFileSelector consistent to how you manage memory in your app).

For more details, you should consult the documentation directly.

  • Related