Qt 如何将QML文件组织到嵌套文件夹中?

Qt 如何将QML文件组织到嵌套文件夹中?,qt,qml,Qt,Qml,我有一个样本项目在 如果我的层次结构如下所示: $ tree qml_location/ qml_location/ ├── MyDeepComponent.qml ├── MyDeepComponentForm.ui.qml ├── main.cpp ├── main.qml ├── qml.qrc └── qml_location.pro import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12

我有一个样本项目在

如果我的层次结构如下所示:

$ tree qml_location/
qml_location/
├── MyDeepComponent.qml
├── MyDeepComponentForm.ui.qml
├── main.cpp
├── main.qml
├── qml.qrc
└── qml_location.pro
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  Column
  {
    MyDeepComponent {}
    MyDeeperComponent {}
  }
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true

  title: qsTr("Hello World")

  property var componentNames: [ "qml/more/MyDeeperComponent.qml", "qml/MyDeepComponent.qml" ]

  function generateObjects()
  {
      function generateOneObject( name )
      {
          var component
          var componentObject

          function finishCreation()
          {
              componentObject = component.createObject( contentColumn );
          }

          component = Qt.createComponent( `qrc:/${name}` )

          if ( component.status === Component.Ready )
          {
              finishCreation()
          }
          else
          {
              component.statusChanged.connect( finishCreation );
          }
      }

      for ( var index in componentNames )
      {
          generateOneObject( componentNames[ index ] )
      }
  }

  Component.onCompleted: {
      generateObjects()
  }

  Column
  {
    id: contentColumn
  }
}
然后我可以编写
main.qml
如下:

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  MyDeepComponent {}
}
它会起作用的

但是,我希望将一些QML文件组织到文件夹层次结构中,而不是让它们都处于同一级别

例如,如果我移动到:

$ tree qml_location/
qml_location/
├── main.cpp
├── main.qml
├── qml
│   ├── MyDeepComponent.qml
│   ├── MyDeepComponentForm.ui.qml
│   └── more
│       ├── MyDeeperComponent.qml
│       └── MyDeeperComponentForm.ui.qml
├── qml.qrc
└── qml_location.pro
并且有一个
main.qml
,看起来像:

$ tree qml_location/
qml_location/
├── MyDeepComponent.qml
├── MyDeepComponentForm.ui.qml
├── main.cpp
├── main.qml
├── qml.qrc
└── qml_location.pro
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  Column
  {
    MyDeepComponent {}
    MyDeeperComponent {}
  }
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true

  title: qsTr("Hello World")

  property var componentNames: [ "qml/more/MyDeeperComponent.qml", "qml/MyDeepComponent.qml" ]

  function generateObjects()
  {
      function generateOneObject( name )
      {
          var component
          var componentObject

          function finishCreation()
          {
              componentObject = component.createObject( contentColumn );
          }

          component = Qt.createComponent( `qrc:/${name}` )

          if ( component.status === Component.Ready )
          {
              finishCreation()
          }
          else
          {
              component.statusChanged.connect( finishCreation );
          }
      }

      for ( var index in componentNames )
      {
          generateOneObject( componentNames[ index ] )
      }
  }

  Component.onCompleted: {
      generateObjects()
  }

  Column
  {
    id: contentColumn
  }
}
Qt Creator告诉我MyDeepComponent和MyDeeperComponent是未知的

当我尝试运行时,我得到一个错误:
MyDeepComponent不是一个类型

我能做些什么才能让它起作用

需要注意的是,我不想在main.qml的顶部放置特殊或额外的导入。这还可能吗

qml.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>qml/MyDeepComponent.qml</file>
        <file>qml/MyDeepComponentForm.ui.qml</file>
        <file>qml/more/MyDeeperComponent.qml</file>
        <file>qml/more/MyDeeperComponentForm.ui.qml</file>
    </qresource>
</RCC>

编辑:我正在阅读你的问题部分,其中你表示不希望在顶部导入。我认为这是不可能的,如果不在主文件夹(对于要创建的每个文件夹)中抛出一堆
addImportPath
,或者大量修改qrc别名。把剩下的答案留给未来的访客,或者如果你改变主意,留给未来的访客;-)


您可以使用
qmldir
文件使它们在所选命名空间中可用。但有一点学习曲线。
qmldir
文件必须位于类似名称空间的文件夹中

例如,如果要使用
MyApplication
作为名称空间,则必须将
qmldir
文件放在文件夹“MyApplication”(在qml导入路径内)中。如果希望
MyOrg.application1
作为名称空间,则必须将
qmldir
放在“MyOrg/application1”中

根据你的情况,我选择第一种选择。我将为可导入的qml文件创建一个单独的qrc文件,如果您想轻松地将所有qml文件放在“qml”文件夹中,也需要该文件:


您可以看到我使用了前缀,这样文件就不必移动。如果您想使用该应用程序达到更高的境界,并且想要一个
MyApplication 2.0
名称空间,您可以使用前缀
/qml/MyApplication.2

您可以执行以下操作:

module MyApplication

MyDeepComponent         1.0 MyDeepComponent.qml
MyDeeperComponent       1.0 more/MyDeeperComponent.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  Column
  {
    Loader {
        source: "qrc:/qml/MyDeepComponent.qml"
    }
    Loader {
        source: "qrc:/qml/more/MyDeeperComponent.qml"
    }
  }
}
虽然我不太清楚你为什么要这么做。可能有助于描述您试图解决的问题?

createObject可用于将组件直接加载到列中

main.qml看起来像:

$ tree qml_location/
qml_location/
├── MyDeepComponent.qml
├── MyDeepComponentForm.ui.qml
├── main.cpp
├── main.qml
├── qml.qrc
└── qml_location.pro
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")
  Column
  {
    MyDeepComponent {}
    MyDeeperComponent {}
  }
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window
{
  width: 640
  height: 480
  visible: true

  title: qsTr("Hello World")

  property var componentNames: [ "qml/more/MyDeeperComponent.qml", "qml/MyDeepComponent.qml" ]

  function generateObjects()
  {
      function generateOneObject( name )
      {
          var component
          var componentObject

          function finishCreation()
          {
              componentObject = component.createObject( contentColumn );
          }

          component = Qt.createComponent( `qrc:/${name}` )

          if ( component.status === Component.Ready )
          {
              finishCreation()
          }
          else
          {
              component.statusChanged.connect( finishCreation );
          }
      }

      for ( var index in componentNames )
      {
          generateOneObject( componentNames[ index ] )
      }
  }

  Component.onCompleted: {
      generateObjects()
  }

  Column
  {
    id: contentColumn
  }
}

这个答案不满足不导入的要求,但无论如何值得一提的是,它可以通过main.qml顶部的几个导入来解决


另一种解决方案是将main.qml移动到qml文件夹中。这允许main.qml查找MyDeepComponent,因为它们是同级。要查找MyDeeperComponent,main.qml可以导入“more”目录

此解决方案在分支中表示

目录结构

$ tree qml_location/

qml_location/
├── main.cpp
├── qml
│   ├── MyDeepComponent.qml
│   ├── MyDeepComponentForm.ui.qml
│   ├── main.qml
│   └── more
│       ├── MyDeeperComponent.qml
│       └── MyDeeperComponentForm.ui.qml
├── qml.qrc
├── qml_location.pro
└── qml_location.pro.user
main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

  QGuiApplication app(argc, argv);

  QQmlApplicationEngine engine;

  const QUrl url(QStringLiteral("qrc:/qml/main.qml"));

  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();
}

添加
import“qml”
import“qml/more”
@eyllanesc,OP说他不想使用
import
。不过,我不确定原因是什么@James Hudson,我还没有尝试过这个方法,但是如果在.qrc文件中使用别名,它可能会起作用。可以使用别名,但在QtCreator中,它们看起来都在同一个文件夹中,因此唯一的好处是在磁盘/git上排序,而不是在IDE中排序@JamesHudson为什么要求不导入?我可以更具体地说,我不希望导入直接导入MyDeepComponent。原因与。。。我将需要动态加载qml文件并减少代码维护,我不希望在需要时添加导入语句。然而,正如@eyllanesc指出的,看起来导入“qml”等是一个可行的选择。我想尝试让这个解决方案工作,但目前我失败了。我有一个名为“qmldir_solution”的分支,在该分支上尝试实现您的建议。尝试了您在上建议的变体,但不幸的是,它也不起作用。您仍然需要
addImportPath(:/qml:);
。我扔掉了我的更改,在垃圾桶里找不到它们,否则我会为您上传它们。我想我的问题是我很难理解和实现您的答案。如果您能提供更多细节或解释我哪里出错,我会感兴趣。我曾尝试添加导入,但没有成功lp.我确实找到了问题的解决方案。正如您在上文中所回避的那样,为了使其正常工作,qmldir和qml文件应该位于名为Components的文件夹中,以了解qmldir如何定义组件。Qt Creator很高兴,代码运行正常。我已经更新了项目,原因与…有关。我将尝试您的解决方案。Wha我将要做的是基于QDirIterator或FolderListModel动态生成这些加载程序对象,以在资源中找到一组QML文件,这些文件定义了需要插入的组件。组件的列表很大,并且会不断增加。我不确定这是否是讨论我的用例的合适论坛。我们可以移动它到或其他地方。为什么不使用该解决方案?动态加载并创建组件?这是一个好问题。在另一个上下文中,我尝试了它,但它不起作用。在这个上下文中尝试了它,但它起作用了。我需要找出原因。无论如何,我尝试了你的加载程序解决方案,它起作用了。