Qt6中带双参数构造函数的QAbstractListModel子类无法在QML实例化的解决方法
Qt6中QML实例化带双参数构造函数的自定义Model失败的解决方法
问题说明
将Qt5可用的硬核粒子系统代码移植到Qt6时,自定义的Hardcore_Entrymodel(继承自QAbstractListModel)因构造函数包含System*和QObject*两个参数,导致QML中实例化时QQmlApplicationEngine加载组件失败。此前Qt5的羊群模拟代码移植正常,换用新模型并升级Qt6后出现该问题,核心原因是QML无法自动提供非默认构造函数的参数。
相关代码
Hardcore_Entrymodel头文件
class Hardcore_Entrymodel : public QAbstractListModel { Q_OBJECT public: explicit Hardcore_Entrymodel(System*, QObject *parent = 0); virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; void populate(); QHash<int, QByteArray> mPropertyNames; enum mParticleProperties{ type = Qt::UserRole, iparticle = Qt::UserRole+1, size_semimajoraxis = Qt::UserRole+2, size_semiminoraxis = Qt::UserRole+3, x_mid_pxl = Qt::UserRole+4, y_mid_pxl = Qt::UserRole+5, xy_angle_degree = Qt::UserRole+6, typecolor = Qt::UserRole+7, }; Q_INVOKABLE void doNewStep(); Q_INVOKABLE void stepReady(); Q_INVOKABLE int returnWindowLx(); Q_INVOKABLE int returnWindowLy(); Q_INVOKABLE int returnSteptime_ms(); bool isNewStep(); void setIsNewStep(bool newS); protected: virtual QHash<int, QByteArray> roleNames() const override; private: System *hardcoresystem; int nparticles; InitQtView initqtview; QList<std::tuple<std::string, int,int,int,int,int, QColor> > mDatas; bool newStep; signals: void newStepDoing(); void newStepReady(); public slots: void onNewStepDone(); };
main函数
#include <QObject> #include <QGuiApplication> #include <QQmlApplicationEngine> #include "Hardcore_InitClass.h" #include "Hardcore_Entrymodel.h" int main(int argc, char *argv[]) { Hardcore_InitClass initClass(argc, argv); System system; initClass.return_Hardcoresystem_single(&system); system.writeParametersFile(); QGuiApplication app(argc, argv); qmlRegisterType<Hardcore_Entrymodel>("org.hardcoresystem", 1, 0, "Hardcore_Entrymodel"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Main.qml"))); return app.exec(); }
QML文件片段
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12 //import QtQuick.Layouts 2.2 import QtQml.Models 2.12 import Qt.labs.qmlmodels 1.0 import org.hardcoresystem 1.0 Window { id: appwindow visible: true width: hardcoreentrymodel.returnWindowLx() height: hardcoreentrymodel.returnWindowLx() Rectangle{ id: hardcoresystemrectangle anchors.left: appwindow.left anchors.top: appwindow.top width: appwindow.width height: appwindow.height color: "white" } Hardcore_Entrymodel{ id: hardcoreentrymodel //onNewPathDoing: console.log("New Path doing ...\n") //onNewPathReady: {console.log("New Path ready ...\n")} //onDataChanged: console.log("DataChanged received") } Timer { id: steptimer interval: Number(hardcoreentrymodel.returnSteptime_ms()) //interval: 100 repeat: true running: true triggeredOnStart: true onTriggered: {hardcoreentrymodel.doNewStep()} } Item{ id: partilcesitem width: hardcoresystemrectangle.width height: hardcoresystemrectangle.height anchors.left: hardcoresystemrectangle.left anchors.top: hardcoresystemrectangle.top Repeater { [...]
解决方案
QML只能调用类的默认构造函数(仅带QObject* parent参数且parent有默认值),因此需要调整构造函数的参数传递方式,以下是三种可行方案:
方案一:通过Q_PROPERTY传递System指针(推荐)
- 修改模型构造函数:改为仅带
QObject* parent的默认构造函数
explicit Hardcore_Entrymodel(QObject *parent = nullptr);
- 添加Q_PROPERTY用于传递System指针:
class Hardcore_Entrymodel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(System* hardcoreSystem READ hardcoreSystem WRITE setHardcoreSystem NOTIFY hardcoreSystemChanged) public: explicit Hardcore_Entrymodel(QObject *parent = nullptr); // 原有成员保持不变 System* hardcoreSystem() const; void setHardcoreSystem(System* system); signals: void hardcoreSystemChanged(); // 原有信号保持不变 private: System *hardcoresystem = nullptr; // 原有成员保持不变 };
- 实现属性的读写方法:
System* Hardcore_Entrymodel::hardcoreSystem() const { return hardcoresystem; } void Hardcore_Entrymodel::setHardcoreSystem(System* system) { if (hardcoresystem == system) return; hardcoresystem = system; emit hardcoreSystemChanged(); // 设置后触发初始化逻辑 populate(); }
- 在main中创建模型并传入System指针:
int main(int argc, char *argv[]) { Hardcore_InitClass initClass(argc, argv); System system; initClass.return_Hardcoresystem_single(&system); system.writeParametersFile(); QGuiApplication app(argc, argv); // 创建模型实例并设置System指针 Hardcore_Entrymodel* model = new Hardcore_Entrymodel(); model->setHardcoreSystem(&system); // 将模型设置为QML上下文属性,供QML直接访问 QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("hardcoreentrymodel", model); engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Main.qml"))); return app.exec(); }
- 修改QML代码:移除模型实例化代码,直接使用上下文传入的
hardcoreentrymodel
Window { id: appwindow visible: true width: hardcoreentrymodel.returnWindowLx() height: hardcoreentrymodel.returnWindowLy() // 修正原代码的笔误 // 移除原有Hardcore_Entrymodel实例化代码 // ... 其他代码保持不变 }
方案二:注册单例模型(适合全局唯一实例)
如果模型只需要一个全局实例,可通过qmlRegisterSingletonType在C++中创建并注册:
- 编写单例创建函数:
static QObject* createHardcoreModel(QQmlEngine* engine, QJSEngine* scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) // 初始化System实例 static System system; Hardcore_InitClass initClass(0, nullptr); initClass.return_Hardcoresystem_single(&system); system.writeParametersFile(); // 创建模型并传入System指针 return new Hardcore_Entrymodel(&system); }
- 注册单例到QML:
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterSingletonType<Hardcore_Entrymodel>("org.hardcoresystem", 1, 0, "Hardcore_Entrymodel", createHardcoreModel); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Main.qml"))); return app.exec(); }
- QML中直接使用单例:
Window { id: appwindow visible: true width: Hardcore_Entrymodel.returnWindowLx() height: Hardcore_Entrymodel.returnWindowLy() // 调用方法时直接使用类型名,无需实例化 }
方案三:使用工厂类创建实例(适合多场景实例)
如果需要在QML中创建多个模型实例,可通过工厂类封装创建逻辑:
- 实现工厂类:
class HardcoreModelFactory : public QObject { Q_OBJECT public: explicit HardcoreModelFactory(System* system, QObject* parent = nullptr) : QObject(parent), m_system(system) {} Q_INVOKABLE Hardcore_Entrymodel* createModel() { return new Hardcore_Entrymodel(m_system); } private: System* m_system; };
- 注册工厂并传入QML上下文:
int main(int argc, char *argv[]) { Hardcore_InitClass initClass(argc, argv); System system; initClass.return_Hardcoresystem_single(&system); system.writeParametersFile(); QGuiApplication app(argc, argv); qmlRegisterType<Hardcore_Entrymodel>("org.hardcoresystem", 1, 0, "Hardcore_Entrymodel"); HardcoreModelFactory* factory = new HardcoreModelFactory(&system); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("modelFactory", factory); engine.load(QUrl(QStringLiteral("qrc:/qt/qml/Main.qml"))); return app.exec(); }
- QML中通过工厂创建实例:
Window { id: appwindow visible: true property var hardcoreentrymodel Component.onCompleted: { hardcoreentrymodel = modelFactory.createModel() } // ... 其他代码使用hardcoreentrymodel }
内容的提问来源于stack exchange,提问作者user24126140
相关产品推荐
相关产品推荐

