You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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指针(推荐)

  1. 修改模型构造函数:改为仅带QObject* parent的默认构造函数
explicit Hardcore_Entrymodel(QObject *parent = nullptr);
  1. 添加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;
    // 原有成员保持不变
};
  1. 实现属性的读写方法:
System* Hardcore_Entrymodel::hardcoreSystem() const
{
    return hardcoresystem;
}

void Hardcore_Entrymodel::setHardcoreSystem(System* system)
{
    if (hardcoresystem == system)
        return;
    hardcoresystem = system;
    emit hardcoreSystemChanged();
    // 设置后触发初始化逻辑
    populate();
}
  1. 在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();
}
  1. 修改QML代码:移除模型实例化代码,直接使用上下文传入的hardcoreentrymodel
Window {
    id: appwindow
    visible: true
    width: hardcoreentrymodel.returnWindowLx()
    height: hardcoreentrymodel.returnWindowLy() // 修正原代码的笔误

    // 移除原有Hardcore_Entrymodel实例化代码
    // ... 其他代码保持不变
}

方案二:注册单例模型(适合全局唯一实例)

如果模型只需要一个全局实例,可通过qmlRegisterSingletonType在C++中创建并注册:

  1. 编写单例创建函数:
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);
}
  1. 注册单例到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();
}
  1. QML中直接使用单例:
Window {
    id: appwindow
    visible: true
    width: Hardcore_Entrymodel.returnWindowLx()
    height: Hardcore_Entrymodel.returnWindowLy()
    // 调用方法时直接使用类型名,无需实例化
}

方案三:使用工厂类创建实例(适合多场景实例)

如果需要在QML中创建多个模型实例,可通过工厂类封装创建逻辑:

  1. 实现工厂类:
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;
};
  1. 注册工厂并传入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();
}
  1. QML中通过工厂创建实例:
Window {
    id: appwindow
    visible: true
    property var hardcoreentrymodel

    Component.onCompleted: {
        hardcoreentrymodel = modelFactory.createModel()
    }
    // ... 其他代码使用hardcoreentrymodel
}

内容的提问来源于stack exchange,提问作者user24126140

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:02:03