将自定义C ++对象传递给Qml错误(无属性)

时间:2015-03-05 07:49:35

标签: c++ qt qml

我正在尝试编写代码,通过信号将一些数据从C ++引擎传递到Qml脚本,但看起来我做错了,因为当我在Qml中收到信号时,我的对象不会发生任何问题方法或属性!看看那段代码:

Signaller - 调用信号的类: signaller.h:

class Signaller : public QObject
{
    Q_OBJECT
public:
    explicit Signaller(QObject *parent = 0);
    Q_INVOKABLE void invokeSignal();
signals:
    void mysignal(TestClass test);
public slots:

};

signaller.cpp:

Signaller::Signaller(QObject *parent) :
    QObject(parent)
{
}

void Signaller::invokeSignal()
{
    TestClass s;
    emit mysignal(s);
}

TestClass - 将传递给Qml引擎的类,它必须在Qml脚本中具有测试方法:

Test.h:

class TestClass : public QObject
{
    Q_OBJECT
public:
    explicit TestClass(QObject *parent = 0);
             TestClass(const TestClass& obj);
             ~TestClass();
     Q_INVOKABLE void test();

signals:

public slots:

};

Q_DECLARE_METATYPE(TestClass)

Test.cpp的:

TestClass::TestClass(QObject *parent) :
    QObject(parent)
{
    qDebug()<<"TestClass::TestClass()";
}

TestClass::TestClass(const TestClass &obj) :
    QObject(obj.parent())
{
    qDebug()<<"TestClass::TestClass(TestClass &obj)";
}


TestClass::~TestClass()
{
    qDebug()<<"TestClass::~TestClass()";
}

void TestClass::test()
{
    qDebug()<<"TestClass::test";
}

这两个类也在主函数中注册:

int main(int argc, char *argv[])
{
    // SailfishApp::main() will display "qml/template.qml", if you need more
    // control over initialization, you can use:
    //
    //   - SailfishApp::application(int, char *[]) to get the QGuiApplication *
    //   - SailfishApp::createView() to get a new QQuickView * instance
    //   - SailfishApp::pathTo(QString) to get a QUrl to a resource file
    //
    // To display the view, call "show()" (will show fullscreen on device).

    qmlRegisterType<TestClass>("Test", 1, 0, "Test");
    qmlRegisterType<Signaller>("Signaller", 1, 0, "Signaller");

    return SailfishApp::main(argc, argv);
}

这是我的带有测试代码的Qml文件:

import Signaller 1.0

Page {

    Signaller {
        id: sig
        Component.onCompleted: sig.invokeSignal()
        onMysignal: {
            console.log("signal",typeof test);
            console.log(typeof test.test);
        }
    }
}

日志:

[D] TestClass::TestClass:6 - TestClass::TestClass() 
[D] TestClass::TestClass:12 - TestClass::TestClass(TestClass &obj) 
[D] TestClass::TestClass:12 - TestClass::TestClass(TestClass &obj) 
[D] onMysignal:41 - signal object
[D] onMysignal:42 - undefined
[D] TestClass::~TestClass:18 - TestClass::~TestClass() 
[D] TestClass::~TestClass:18 - TestClass::~TestClass() 

从log中可以看出,TestClass.test字段在传递给Qml后为空。 我做错了什么?

3 个答案:

答案 0 :(得分:6)

您正在通过信号/广告位系统按值传递QObject派生对象 - 您应从不执行此操作(docs)。在堆上创建它并发送它的指针。

在这种情况下,您可能希望通过QML控制其生命周期,您可以通过调用QQmlEngine::setObjectOwnership( s, QQmlEngine::JavaScriptOwnership)来设置它。

答案 1 :(得分:3)

信号和插槽中的值不应使用

QObject。此外,当QObject本身隐藏其复制构造函数时,为QObject子类实现复制构造函数是一个坏主意。

因此改变你的信号以传递指向QObject的指针,它会没事的。有一个short and good reference on how to communicate between C++ and Qml

ps:您不需要注册声明Q_OBJECT宏的类。

答案 2 :(得分:2)

这是我为自己测试C ++而做的一个例子&lt; - &gt; QML互动:

//File: animal.h
#ifndef ANIMAL_H
#define ANIMAL_H

#include <QObject>

class Animal : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString animal_name READ get_animal_name WRITE set_animal_name)
public:
    explicit Animal(QObject *parent = 0);
    QString get_animal_name();
    void set_animal_name(QString p_name);
private:
    QString     animal_name;

};

#endif // ANIMAL_H

//File: animal.cpp
#include "animal.h"

Animal::Animal(QObject *parent) : QObject(parent)
{
}
void Animal::set_animal_name(QString p_name) {
    animal_name=p_name;
}
QString Animal::get_animal_name() {
    return animal_name;
}

//File: zoo.h
#ifndef ZOO_H
#define ZOO_H

#include <QObject>

class Animal;
class Zoo : public QObject
{
    Q_OBJECT
public:
    explicit Zoo(QObject *parent = 0);
    Q_INVOKABLE Animal* get_animal_by_index(int index);
    Q_INVOKABLE void add_animal(Animal *a);
    Q_INVOKABLE void dump_animal_info(Animal *a);
    Q_INVOKABLE void emit_signal();
signals:
    void some_signal(Animal *animal_object);
public slots:

private:
       QList<Animal*>       animals;
};

#endif // ZOO_H


//File: zoo.cpp
#include <QDebug>
#include "zoo.h"
#include "animal.h"

Zoo::Zoo(QObject *parent) : QObject(parent)
{
    Animal *a;

    a=new Animal();
    a->set_animal_name("Black Bear");
    add_animal(a);

    a=new Animal();
    a->set_animal_name("Gray Wolf");
    add_animal(a);
}
Animal* Zoo::get_animal_by_index(int index) {
    return animals.at(index);
}
void Zoo::add_animal(Animal *a) {
    animals.append(a);
}
void Zoo::dump_animal_info(Animal *a) {
    qWarning() << "animal_name=" << a->get_animal_name();
}
void Zoo::emit_signal() {
    Animal *a;
    a=animals.at(0);
    emit some_signal(a);
}

//File: main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "animal.h"
#include "zoo.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<Zoo>("zoo",1,0,"Zoo");
    qmlRegisterType<Animal>("zoo.animal",1,0,"Animal");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

//File: main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

import zoo 1.0
import zoo.animal 1.0

ApplicationWindow {
    visible: true
    width: 640; height: 480; title: qsTr("Zoo")

    Zoo {
        id: zoopark
    }
    Column {
        Button {
            text: "Test C++ <--> QML data exchange by Method"
            onClicked: {
                var animal=zoopark.get_animal_by_index(1);
                zoopark.dump_animal_info(animal);
            }
        }
        Button {
            text: "Text C++ <--> QML data exchage by Signal"
            onClicked: {
                zoopark.emit_signal();
            }
        }
    }
    Connections {
        target: zoopark
        onSome_signal: {
            console.log('signal received');
            console.log('from qml: animal name=' + animal_object.animal_name)
            console.log('dumping animal info from c++:')
            zoopark.dump_animal_info(animal_object)
        }
    }

    function process_signal() {
        console.log('from qml animal name=' + animal_object.animal_name)
        zoopark.dump_animal_info(animal_object)
    }
}