More then one qmldir file?



  • Hello,
    it seems not possible to have multiple directories with a qmldir file in each. Here's a short Test:
    My file structure looks like this:

    Colors1\
      Colors1.qml
      qmldir
    Colors2\
      Colors2.qml
      qmldir
    main.qml
    

    And the contents of the files:
    Colors1/Colors1.qml:

    pragma Singleton
    import QtQuick 2.0
    
    QtObject {
      property color background: "black"
    }
    

    Colors1/qmldir:

    singleton Colors1 Colors1.qml
    

    Colors2/Colors2.qml:

    pragma Singleton
    import QtQuick 2.0
    
    QtObject {
      property color foreground: "red"
    }
    

    Colors2/qmldir:

    singleton Colors2 Colors2.qml
    

    main.qml:

    import QtQuick 2.6
    import QtQuick.Controls 1.5
    import "." // this import is needed cause of QTBUG-34418
    
    ApplicationWindow {
      visible: true
      width: 640
      height: 480
      title: qsTr("QrcTest")
    
      color: Colors1.background
    
      Text {
        anchors.centerIn: parent
        color: Colors2.foreground
        text: "Hello world!"
      }
    }
    

    When I run this project it outputs the error:

    qrc:/main.qml:15: ReferenceError: Colors2 is not defined
    

    When I remove Colors1.qrc from RESOURCES definition in project and run the project again (with a forced rebuild before) it outputs the Error:

    qrc:/main.qml:11: ReferenceError: Colors1 is not defined
    

    which is correct but Color2 is now defined and works as expected.
    Isn't it possible to have multiple qmldir files in one project?



  • How are your resources organized? Are you using aliases/prefixes, or multiple .qrc files? Could you paste the contents of the .qrc file? I would expect you to import "Colors1" and "Colors2". If you can access the singleton(s) via import "." then the problem might be in the resource tree, which doesn't reflect the directory tree on the file system? Perhaps one qmldir file quietly overrides the other?



  • @jpnurmi Oh, yes I forgot the qrc files. In each of Colors1/Colors2 I have a colors1.qrc or colors2.qrc respectively.
    colors1.qrc:

    <RCC>
        <qresource prefix="/">
            <file>Colors1.qml</file>
            <file>qmldir</file>
        </qresource>
    </RCC>
    

    colors2.qrc

    <RCC>
        <qresource prefix="/">
            <file>Colors2.qml</file>
            <file>qmldir</file>
        </qresource>
    </RCC>
    

    So no aliases nor prefixes.
    One overrides the other is what I think too. I noticed it's also not possible to have multiple qrc files with the same name. They override each other no matter in which directory they are. (I think it's a bug in qmake.)
    The problem with qmldir files is that I can't rename them.
    Is there a workaround? Perhaps with modules?



  • You have two .qrc files that both have a qmldir file with prefix /. Thus, you have two instances of :/qmldir.

    Either you will have to specify the prefixes (*):

    Colors1/colors1.qrc:

    <RCC>
        <qresource prefix="/Colors1">
            <file>Colors1.qml</file>
            <file>qmldir</file>
        </qresource>
    </RCC>
    

    Colors2/colors2.qrc:

    <RCC>
        <qresource prefix="/Colors2">
            <file>Colors2.qml</file>
            <file>qmldir</file>
        </qresource>
    </RCC>
    

    Or alternatively, you get unique names if you have those listed in the same .qrc like this:

    /colors.qrc:

    <RCC>
        <qresource prefix="/">
            <file>Colors1/Colors1.qml</file>
            <file>Colors1/qmldir</file>
            <file>Colors2/Colors2.qml</file>
            <file>Colors2/qmldir</file>
        </qresource>
    </RCC>
    

    Furthermore, in QML, you will import "Colors1" and "Colors2", respectively.

    (*) The name of the directory where a .qrc file is located at build time does not matter.



  • @jpnurmi I just tested your first alternative. I had to add the import statements for the new prefixes but now it works. Thanks! I never played with prefixes cause I didn't really know what they are good for.
    My first approach was to import them as modules but it didn't work cause of the subdirectories. Do you know how to turn Colors1/Colors2 into modules which get imported like that:

    import Colors1 1.0
    


  • You could register the modules from C++, for example by using qmlRegisterSingletonType() for the singletons:

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        qmlRegisterSingletonType(QUrl("qrc:/Colors1/Colors1.qml"), "Colors1", 1, 0, "Colors1");
        qmlRegisterSingletonType(QUrl("qrc:/Colors2/Colors2.qml"), "Colors2", 1, 0, "Colors2");
    
        QQmlApplicationEngine engine;
        engine.load("qrc:/main.qml");
    
        return app.exec();
    }


  • @jpnurmi OK that works as well. Thanks again!
    I tried the qml way with a qmldir like that:

    module Colors1
    singleton Colors1 1.0 Colors1.qml
    

    That didn't work. I don't know why but the module wasn't found.
    I would prefer that way cause it looks much cleaner and I wanted to keep it in qml.
    Do you know the reason for the error:

    qrc:/main.qml:11: ReferenceError: Colors1 is not defined
    


  • So, quoted imports work for paths and URLs, and paths can be relative to the .qml file that contains the import. However, in order to import a QML module by its name instead, the QML engine must be able to locate the module in one of its import paths. You can add import paths using QQmlEngine::addImportPath().

    Notice that this is the path that contains the module directory ie. not the module directory itself but its parent directory. In other words, a directory where the QML engine can locate a sub-directory by the name of the imported module.

    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.addImportPath("qrc:/"); // if that's where the ColorsN folders are
        engine.load(...);
    
        return app.exec();
    }
    


  • @jpnurmi With addImportPath it runs without error, but QtCreator still complains about the missing module Colors1 (Qml module not found (Colors1)). I added the line

    QML_IMPORT_PATH = Colors1
    

    but it didn't help. Even though the hint popup window which pops up when I hover the mouse pointer over the underlined import Colors1 1.0 line shows the correct import path.



  • Similarly to that QQmlEngine::addImportPath() should point to the path that contains the module directory, I'd assume the same for the Qt Creator's QML_IMPORT_PATH qmake variable. So perhaps something like QML_IMPORT_PATH = $$PWD or QML_IMPORT_PATH = .?



  • @jpnurmi All right, now everything works w/o any error. Thank you very much! I didn't know that it's so complicated and confusing.
    To summarize:
    If the goal is to have more than one qmldir files and everything should be stored in the resource system:
    (Keep in mind getting it running has nothing to do with making QtCreator happy!)
    To get it running:

    • A qrc file listing one of the qmldir files has to have a unique prefix. The name of the prefix doesn't matter, it even doesn't have to match the name of the containing directory! The prefix is the name of the module getting imported!
    • The qmldir file doesn't even have to contain a line defining the name of the module!

    To make QtCreator happy:

    • The name of the module to be imported has to be equal to the name of the directory the qmldir file lives in
    • The QML_IMPORT_PATH (BTW: QML2_IMPORT_PATH doesn't work at all.) has to point to the parent of that directory.

    Example:
    Directory structure (The uppercase letters at the end of "Colors"/"colors" are just to show which names have to match and which don't. It should work without these letters as well.):

    ColorsA
      colorsB.qrc
      ColorsC.qml
      qmldir
    qml.qrc
    main.qml
    Test.pro
    

    colorsB.qrc:

    <RCC>
        <qresource prefix="/ColorsA">
            <file>ColorsC.qml</file>
            <file>qmldir</file>
        </qresource>
    </RCC>
    

    ColorsC.qml:

    pragma Singleton
    import QtQuick 2.0
    
    QtObject {
      property color background: "black"
    }
    

    qmldir:

    singleton ColorsD 1.0 ColorsC.qml
    

    qml.qrc:

    <RCC>
        <qresource prefix="/">
            <file>main.qml</file>
        </qresource>
    </RCC>
    

    main.qml:

    import QtQuick.Controls 1.0
    import ColorsA 1.0
    
    ApplicationWindow {
      visible: true
      width: 640
      height: 480
      title: qsTr("Test")
    
      color: ColorsD.background
    }
    

    Test.pro:

    ...
    QML_IMPORT_PATH = .
    ...
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.