Qt6 QML自定义组件、资源系统、模块化。

1. 模块化

项目文件本身就是一个模块

qt_add_qml_module(${PROJECT_NAME} # 默认导入项目的
    URI QPlayer
    VERSION 1.0
    QML_FILES 
        main.qml

各模块路径是平级的,qmldir可以完全使用qt_add_qml_module代替,qt_add_qml_module更现代化,集中配置

1.1 模块内访问

同一模块内部:

qml组件名开头必须大写

方式零

导入的组件在同级目录,可以直接访问,不用导入

project/
 ├─ CMakeLists.txt
 ├─ A.qml
 └─ B.qml
// A.qml内

	B {
		 anchors.bottom: parent.bottom
	}

方式一:相对路径导入(无 qmldir

📂 目录结构

project/
 ├─ CMakeLists.txt
 ├─ main.qml
 └─ layout/
     ├─ Theme.qml
     └─ BottomBar.qml

main.qml

import QtQuick
import "./layout" // 导入这个目录下的所有qml

Window {
    width: 400
    height: 300
    visible: true

    BottomBar { anchors.bottom: parent.bottom }
}

方式二:模块名导入(有 qmldir

一旦目录下存在 qmldir,该目录就会被视为 独立模块,必须使用模块名导入。

📂 目录结构

project/
 ├─ CMakeLists.txt
 ├─ main.qml
 └─ layout/
     ├─ qmldir
     ├─ Theme.qml
     └─ BottomBar.qml
1) qmldir 写法

layout/qmldir

module MyApp.Layout
Theme 1.0 Theme.qml
BottomBar 1.0 BottomBar.qml

main.qml

import QtQuick
import MyApp.Layout 1.0

Window {
    width: 400
    height: 300
    visible: true

    BottomBar { anchors.bottom: parent.bottom }
}
2)qt_add_qml_module 等价写法
qt_add_qml_module(my_app
    URI MyApp.Layout
    VERSION 1.0
    QML_FILES
        layout/Theme.qml
        layout/BottomBar.qml
)

效果完全等价,CMake 会自动生成 qmldir


1.2 模块间访问

项目可以有多个子模块,彼此之间通过模块名导入。

📂 目录结构

project/
 ├─ CMakeLists.txt
 ├─ main.qml
 ├─ layout/
 │   ├─ Theme.qml
 │   └─ BottomBar.qml
 └─ controls/
     └─ PlayButton.qml

1)qmldir 写法

layout/qmldir

module MyApp.Layout
Theme 1.0 Theme.qml
BottomBar 1.0 BottomBar.qml

controls/qmldir

module MyApp.Controls
PlayButton 1.0 PlayButton.qml

main.qml

import QtQuick
import MyApp.Layout 1.0
import MyApp.Controls 1.0

Window {
    width: 400; height: 300; visible: true
    BottomBar { anchors.bottom: parent.bottom }
    PlayButton { anchors.centerIn: parent }
}

2)qt_add_qml_module 等价写法

qt_add_qml_module(my_app
    URI MyApp.Layout
    VERSION 1.0
    QML_FILES
        layout/Theme.qml
        layout/BottomBar.qml
)

qt_add_qml_module(my_app
    URI MyApp.Controls
    VERSION 1.0
    QML_FILES
        controls/PlayButton.qml
)

单例的话模块内不用import或者用相对相对路径,可以直接用文件名访问属性


2. 模块打包方式

2.1 使用文件系统

开发阶段,QML 文件直接存在于磁盘,修改后立即生效。

qt_add_qml_module(my_app
    URI MyApp
    VERSION 1.0
    QML_FILES
        main.qml
        layout/Theme.qml
        layout/BottomBar.qml
)

运行时:

QQmlApplicationEngine engine;
engine.loadFromModule("MyApp", "Main");

图片、资源可用磁盘路径引用:

Image { source: "images/icon.png" }

2.2 使用 .qrc

资源打进二进制,跨平台一致。qt访问时,会当作一个文件系统,内部文件依然可以使用相对路径访问其他文件

resources.qrc

<RCC>
    <qresource prefix="/MyApp">
        <file>qml/Main.qml</file>
        <file>qml/Component.qml</file>
        <file>images/icon.png</file>
    </qresource>
</RCC>
qt_add_qml_module(my_app
    URI MyApp
    VERSION 1.0
    QML_FILES
        qml/Main.qml
        qml/Component.qml
    RESOURCES
        resources.qrc
)

使用:

import QtQuick
import MyApp 1.0

Window {
    Component { MyComponent { } }
    Image { source: "qrc:/MyApp/images/icon.png" }
}

3. QML 单例

3.1 C++ 注册单例

qmlRegisterSingletonType(QUrl("qrc:/MySingleton.qml"),
                         "MyApp.Singleton", 1, 0,
                         "MySingleton");

3.2 qmldir + pragma Singleton

📂 目录结构

project/
 ├─ CMakeLists.txt
 ├─ main.qml
 └─ singletons/
     └─ MySingleton.qml

MySingleton.qml

pragma Singleton
import QtQuick

QtObject {
    property string appName: "My App"
}

1)qmldir 写法

singletons/qmldir

module MyApp.Singleton
singleton MySingleton 1.0 MySingleton.qml

main.qml

import QtQuick
import MyApp.Singleton 1.0

Window {
    visible: true
    Text { text: MySingleton.appName }
}

2)qt_add_qml_module 等价写法

# 标记为 QML 单例  要写在qt_add_qml_module 前
set_source_files_properties(singletons/MySingleton.qml
    PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
    
qt_add_qml_module(my_app
    URI MyApp.Singleton
    VERSION 1.0
    QML_FILES
        singletons/MySingleton.qml
)

QML 中仍然:

import MyApp.Singleton 1.0
Text { text: MySingleton.appName }
同模块的也需要 import自身模块来包含单例
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QPlayer 1.0 // 自身模块

Rectangle{
    // 使用ColumnLayout组织左侧边栏内容
    ColumnLayout {
        Text {
            text: "左侧边栏"
            font.pointSize: 20
            color: Theme.currentTheme.fontColor // 单例组件属性
        }
    }
}


4. 动态加载组件

方法 1:Loader

Window {
    Loader {
        id: dynLoader
        anchors.centerIn: parent
    }

    Button {
        text: "Load"
        onClicked: dynLoader.source = "MyComponent.qml"
    }
}

方法 2:Component + createObject

Window {
    Component {
        id: myComp
        MyComponent { }
    }

    Button {
        text: "Create"
        onClicked: myComp.createObject(parent, { "x": 100, "y": 100 })
    }
}

📌 总结

  1. qmldir → 可用相对路径导入。
  2. qmldir → 必须用模块名导入。
  3. 现代 Qt 推荐用 qt_add_qml_module,自动生成 qmldir
  4. 资源打包 可用文件系统或 .qrc,不影响模块语义。
  5. 单例 有两种方式:C++ 注册 / qmldir + pragma Singleton

posted @ 2025-08-17 17:16  丘狸尾  阅读(23)  评论(0)    收藏  举报