我正在尝试使用 qml 构建一个 Qt 项目。qml 元类型注册仅查看顶级 qml 目录。我也想让它查看子目录。
该项目的结构如下:
./CMakeLists.txt
./ui
./ui/MainWindow.qml
./src
./src/controller
./src/controller/Foo.cpp
./src/controller/FileController.cpp
./src/controller/FileController.h
./main.cpp
Run Code Online (Sandbox Code Playgroud)
我的 CMakeLists.txt 如下所示:
cmake_minimum_required(VERSION 3.25)
project(testproject)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick Widgets)
qt_standard_project_setup()
qt_add_executable(testproject)
target_sources(testproject PRIVATE
main.cpp
)
target_link_libraries(testproject PRIVATE
Qt6::Widgets
Qt6::Gui
Qt6::Quick
)
set_target_properties(testproject PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
OUTPUT_NAME some_test_exec
)
target_include_directories(testproject PUBLIC ${PROJECT_SOURCE_DIR}/include)
qt_add_qml_module(testproject
URI testproject
VERSION 1.0
SOURCES
src/controller/FileController.h
src/controller/FileController.cpp
QML_FILES
ui/MainWindow.qml
)
Run Code Online (Sandbox Code Playgroud)
我有一个启动应用程序的主函数:
#include <iostream>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char* argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/testproject/ui/MainWindow.qml"_qs);
engine.load(url);
return app.exec();
}
Run Code Online (Sandbox Code Playgroud)
我在 MainWindow.qml 中创建了一个简单的 qml 文件
ui/MainWindow.qml
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
import QtQuick
import QtQuick.Controls
ApplicationWindow {
id: mainwindow
visible: true
width: 640
height: 480
menuBar: MenuBar {
Menu {
title: "File"
MenuItem { text: "open" }
}
}
}
Run Code Online (Sandbox Code Playgroud)
在里面
src/controller
Run Code Online (Sandbox Code Playgroud)
子目录中,我创建以下头文件 FileController.h
#include <QObject>
#include <QtQml/qqmlregistration.h>
class FileController : public QObject {
Q_OBJECT
QML_ELEMENT // WITHOUT THIS IT COMPILES FINE
Q_PROPERTY(QString file READ name WRITE setName NOTIFY filenameChanged)
private:
QString filename;
void setName(QString name);
public:
FileController(QObject *parent);
QString name();
signals:
void filenameChanged();
};
Run Code Online (Sandbox Code Playgroud)
以及 FileController.cpp 中的一些实现细节
#include "FileController.h"
FileController::FileController(QObject *parent) : QObject(parent) {}
void FileController::setName(QString name) {filename = name;}
QString FileController::name() {return filename;}
Run Code Online (Sandbox Code Playgroud)
编译时,我收到以下错误:
[13/19] Building CXX object CMakeFiles/test....dir/testproject_qmltyperegistrations.cpp.o
FAILED: CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o
/usr/bin/c++ -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_QMLINTEGRATION_LIB -DQT_QMLMODELS_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_WIDGETS_LIB -I/some/test/directory/build/testproject_autogen/include -I/ome/test/directory/include -I/some/test/directory -isystem /usr/include/qt6/QtQml/6.4.1 -isystem /usr/include/qt6/QtQml/6.4.1/QtQml -isystem /usr/include/qt6/QtCore/6.4.1 -isystem /usr/include/qt6/QtCore/6.4.1/QtCore -isystem /usr/include/qt6/QtCore -isystem /usr/include/qt6 -isystem /usr/lib/qt6/mkspecs/linux-g++ -isystem /usr/include/qt6/QtQml -isystem /usr/include/qt6/QtQmlIntegration -isystem /usr/include/qt6/QtNetwork -isystem /usr/include/qt6/QtWidgets -isystem /usr/include/qt6/QtGui -isystem /usr/include/qt6/QtQuick -isystem /usr/include/qt6/QtQmlModels -isystem /usr/include/qt6/QtOpenGL -fPIC -std=c++17 -MD -MT CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o -MF CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o.d -o CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o -c /some/test/directory/build/testproject_qmltyperegistrations.cpp
/some/test/directory/qt/qml_in_other_dir/build/testproject_qmltyperegistrations.cpp:10:10: fatal error: FileController.h: No such file or directory
10 | #include <FileController.h>
Run Code Online (Sandbox Code Playgroud)
显然,在注册 qml 元类型时,Qt 不会在子目录中查找相应的标头。或者它应该复制它们,但没有。它的包含路径中的目录中没有 FileController.h。
编辑:问题仍然发生,例如将 Filecontroller.h 放入
./include/controller/
Run Code Online (Sandbox Code Playgroud)
并添加
include
Run Code Online (Sandbox Code Playgroud)
到 target_include_directories 并将 FileController.cpp 中的包含路径调整为类似的内容
#include <controller/FileController.h>
Run Code Online (Sandbox Code Playgroud)
您需要添加include_directories(src/controller)到 CMake 文件或将包含设置为#include <src/controller/FileController.h>.
看看这个SO问题。
编辑:我发现这些错误报告QTBUG-87221,QTBUG-101146。该补丁在文档中添加了一条注释:
声明 QML 类型的所有标头都需要可以访问,而无需从项目的包含路径中添加任何前缀。