简体   繁体   English

QML 单调样式嵌套文件

[英]QML singletone style nested files

I've got a defined style for the QML application as a separate file MyStyle.qml :我已经为 QML 应用程序定义了样式作为单独的文件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 .我想用另一个超分辨率文件修改它 >2k MyStyle_2k.qml

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

The style is registered in main.cpp :样式在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. QQmlApplicationEngine 无法加载组件 qrc:/path/other_file.qml: Type MyStyle/MyStyle unavailable:9:1: Composite Singleton Type MyStyle 不可创建。

Is it possible to modify qml singleton by another file?是否可以通过另一个文件修改 qml singleton?

You are trying to create an instance of a singleton type which is not possible hence the error message.您正在尝试创建 singleton 类型的实例,这是不可能的,因此会出现错误消息。 If you want to create an instance of the style and modify it inside QML you need to use qmlRegisterType().如果你想创建样式的实例并在 QML 中修改它,你需要使用 qmlRegisterType()。

Or you need to write MyStyle.color1: "#000000" to modify the singleton value.或者你需要写MyStyle.color1: "#000000"来修改 singleton 的值。

EDIT: You could create an instantiable style like InternalMyStyle.qml set all the default values there and re-use it in MyStyle.qml and MyStyle_2k.qml as shown below.编辑:您可以创建一个可实例化的样式,如InternalMyStyle.qml ,在那里设置所有默认值,然后在MyStyle.qmlMyStyle_2k.qml中重新使用它,如下所示。 Both MyStyle.qml and MyStyle_2k.qml are still singletons. MyStyle.qmlMyStyle_2k.qml仍然是单例。

InternalMyStyle.qml InternalMyStyle.qml

import QtQuick

QtObject {
    property color color1: "#ff00ff"
}

MyStyle.qml我的风格.qml

pragma Singleton
import QtQuick

InternalMyStyle {}

MyStyle_2k.qml我的风格_2k.qml

pragma Singleton
import QtQuick

InternalMyStyle {
    color1: "#ff0000"
}

main.cpp主.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QScreen>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

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

    QUrl styleUrl;

    if (screenHeight > 1440)
        styleUrl = QUrl(u"qrc:/untitledMyStyle/MyStyle_2k.qml"_qs);
    else
        styleUrl = QUrl(u"qrc:/untitledMyStyle/MyStyle.qml"_qs);

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

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/untitledMyStyle/main.qml"_qs);
    QObject::connect(
        &engine,
        &QQmlApplicationEngine::objectCreated,
        &app,
        [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        },
        Qt::QueuedConnection);

    engine.load(url);

    return app.exec();
}

CMakeLists.txt CMakeLists.txt

...
qt_add_qml_module(appuntitledMyStyle
    URI untitledMyStyle
    VERSION 1.0
    QML_FILES
        main.qml
        MyStyle.qml
        MyStyle_2k.qml
        InternalMyStyle.qml
)
...

You should name both of your files MyStyle.qml but organize them in the following way:您应该将这两个文件命名为MyStyle.qml ,但按以下方式组织它们:

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.然后,您可以通过使用文件选择器让 Qt 知道要加载哪个版本的MyStyle.qml Note the usage of the plus sign + as a prefix to highres .请注意加号+作为highres前缀的用法。 This is how Qt organizes file overrides based on default or custom file selectors.这就是 Qt 基于默认或自定义文件选择器组织文件覆盖的方式。 The easiest way to declare highres as a custom file selector is via QT_FILE_SELECTOR environment variable, egQT_FILE_SELECTOR highres变量,例如

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.此代码需要在您的main.cpp中尽早发生,因为QT_FILE_SELECTOR将被检查一次并且以后不会被重新检查。

From https://doc.qt.io/qt-6/qfileselector.html :来自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.将从 QT_FILE_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:如果您不想使用QT_FILE_SELECTOR环境变量,那么,为 QML 使用定义文件选择器的正确方法是通过 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.使用QQmlFileSelector的优点是您可以控制在运行时处于活动状态的文件选择器。 ie 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).但是,它是以额外的编码要求为代价的,因为您需要实例化 QQmlFileSelector 配置它,强制重新加载组件(这对于单例来说更难),并在程序退出时清理代码(注意我没有提供任何这些,因为如何实例化和发布 QQmlFileSelector 与您在应用程序中管理 memory 的方式一致,这取决于您。

For more details, you should consult the documentation directly.有关更多详细信息,您应该直接查阅文档。

The only working solution I found is using single file as singleton Style.qml with state group.我找到的唯一可行的解决方案是使用单个文件作为 singleton Style.qml 和 state 组。

main.cpp主.cpp

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

    if(screenHeight > 1440){
        engine.rootContext()->setContextProperty("StyleState", "2k");
    }else{
        engine.rootContext()->setContextProperty("StyleState", "");
    }
...

State.qml State.qml

pragma Singleton
import QtQuick 2.15
import QtQml 2.15

QtObject {
    id: root

    property var widthA: 50
    property var widthB: 100
    
    property alias customStyle: customState.state // alias for call dircectly from qml

    property var states: StateGroup{
        id: customState
        state: StyleState
        states: [
            State{
                name: "2k"
                PropertyChanges{
                    target: root
                    widthA: 100
                    widthB: 200
                }
            }
        ]
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM