Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. More then one qmldir file?
Forum Updated to NodeBB v4.3 + New Features

More then one qmldir file?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
11 Posts 2 Posters 6.3k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • DuBuD Offline
    DuBuD Offline
    DuBu
    wrote on last edited by
    #1

    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?

    1 Reply Last reply
    0
    • jpnurmiJ Offline
      jpnurmiJ Offline
      jpnurmi
      wrote on last edited by jpnurmi
      #2

      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?

      DuBuD 1 Reply Last reply
      2
      • jpnurmiJ jpnurmi

        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?

        DuBuD Offline
        DuBuD Offline
        DuBu
        wrote on last edited by
        #3

        @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?

        1 Reply Last reply
        0
        • jpnurmiJ Offline
          jpnurmiJ Offline
          jpnurmi
          wrote on last edited by jpnurmi
          #4

          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.

          DuBuD 1 Reply Last reply
          2
          • jpnurmiJ jpnurmi

            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.

            DuBuD Offline
            DuBuD Offline
            DuBu
            wrote on last edited by
            #5

            @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
            
            1 Reply Last reply
            0
            • jpnurmiJ Offline
              jpnurmiJ Offline
              jpnurmi
              wrote on last edited by
              #6

              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();
              }
              
              DuBuD 1 Reply Last reply
              2
              • jpnurmiJ jpnurmi

                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();
                }
                
                DuBuD Offline
                DuBuD Offline
                DuBu
                wrote on last edited by DuBu
                #7

                @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
                
                1 Reply Last reply
                0
                • jpnurmiJ Offline
                  jpnurmiJ Offline
                  jpnurmi
                  wrote on last edited by jpnurmi
                  #8

                  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();
                  }
                  
                  DuBuD 1 Reply Last reply
                  2
                  • jpnurmiJ jpnurmi

                    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();
                    }
                    
                    DuBuD Offline
                    DuBuD Offline
                    DuBu
                    wrote on last edited by
                    #9

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

                    1 Reply Last reply
                    0
                    • jpnurmiJ Offline
                      jpnurmiJ Offline
                      jpnurmi
                      wrote on last edited by
                      #10

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

                      DuBuD 1 Reply Last reply
                      2
                      • jpnurmiJ jpnurmi

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

                        DuBuD Offline
                        DuBuD Offline
                        DuBu
                        wrote on last edited by DuBu
                        #11

                        @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:

                        module ColorsA
                        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 = .
                        ...
                        
                        1 Reply Last reply
                        2

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved