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

QML中使用QWidget子类导致程序崩溃,求解决方案

问题:继承QWidget的C++类在QML中使用导致崩溃

尝试在Qt C++中创建继承自QWidget的类,将其添加到QML时程序崩溃,崩溃前QDebug打印出"Constructed"。若改为继承QObject则程序运行正常,求修复建议。

相关代码

MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QWidget>

class MyClass : public QWidget
{
private:
    Q_OBJECT

public:
    MyClass(QWidget *parent = nullptr);
    ~MyClass();

};

#endif // MYCLASS_H

MyClass.cpp

#include "myclass.h"
#include <QDebug>

MyClass::MyClass(QWidget *parent): QWidget(parent)
{
    qDebug() << "Constructed";
}

MyClass::~MyClass()
{
    qDebug() << "Deconstructed";
}

main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>

#include "myclass.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qmlRegisterType <MyClass> ("MyImport", 1, 0, "MyObject");

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/RectTest/main.qml"_qs);
    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();
}

main.qml

import QtQuick
import MyImport 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    MyObject {
        id: obj
    }
}

问题原因与修复方案

  • 核心原因:QWidget属于Qt Widgets模块,遵循传统桌面控件的生命周期与渲染逻辑;而QML基于Qt Quick框架,元素继承自QQuickItem,两者底层机制不兼容,无法直接将QWidget子类注册为QML类型实例化。

方案1:将QWidget嵌入QML

若只是需要在QML界面中显示现有QWidget控件,无需将其注册为QML类型,可通过QWidget::createWindowContainer将Widget包装为QML可识别的容器:
修改main.cpp相关代码:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/RectTest/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [&](QObject *obj, const QUrl &objUrl) {
        if (obj && url == objUrl) {
            // 创建MyClass实例并包装为QML容器
            MyClass *widget = new MyClass();
            QQuickWidget *container = QWidget::createWindowContainer(widget, obj);
            container->setPosition(50, 50);
            container->setFixedSize(200, 200);
        } else if (!obj && url == objUrl) {
            QCoreApplication::exit(-1);
        }
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

同时删除QML中的MyObject声明。

方案2:实现QML原生自定义控件

若需要创建可直接在QML中使用的自定义控件,应继承Qt Quick的QQuickPaintedItem(适用于需要手动绘制的场景)或QQuickItem:
修改MyClass.h:

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QQuickPaintedItem>
#include <QPainter>

class MyClass : public QQuickPaintedItem
{
    Q_OBJECT
public:
    explicit MyClass(QQuickItem *parent = nullptr);
    ~MyClass();

    // 重写paint方法实现自定义绘制
    void paint(QPainter *painter) override;
};

#endif // MYCLASS_H

修改MyClass.cpp:

#include "myclass.h"
#include <QDebug>

MyClass::MyClass(QQuickItem *parent): QQuickPaintedItem(parent)
{
    qDebug() << "Constructed";
}

MyClass::~MyClass()
{
    qDebug() << "Deconstructed";
}

void MyClass::paint(QPainter *painter)
{
    // 示例:绘制红色矩形
    painter->setBrush(Qt::red);
    painter->drawRect(boundingRect());
}

main.cpp中的注册代码保持不变,QML中的MyObject声明也可以正常使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:35:20