QML与C++混合编程详解(四)

2015-01-22 21:04:23 · 作者: · 浏览: 19
ML传递过来的函数参数和返回值会被转换为C++中的QVariant类型,成功返回true,参数不正确或被调用函数名错误返回false,invokeMethod()共有四个重载函数,用法相似。必须使用Q_ARG()宏来声明函数参数,用Q_RETURN_ARG()宏来声明函数返回值,其原型如下:

        QGenericArgument           Q_ARG(Type, const Type & value)
        QGenericReturnArgument     Q_RETURN_ARG(Type, Type & value)

使用QObject::connect()可以连接QML中的信号,connect()共有四个重载函数,它们都是静态函数。必须使用SIGNAL()宏来声明信号,SLOT()宏声明槽函数。

使用QObject::disconnect()可以解除信号与槽函数的连接。

(1)修改main.qml

import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
    visible: true
    width: 360; height: 360
    title: "Union Lotto Game"
    color: "white"
    signal qmlSignal(string message)
    onQmlSignal: console.log("qml signal message is", message) // this is a qml signal
    function qmlFunction(parameter) {
        console.log("qml function parameter is", parameter) // Hello from C++
        return "function from qml"
    }
    Rectangle {
        objectName: "rect"
        anchors.fill: parent
        color: "yellow"
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            gemini.begin()
            gemini.stop()
            gemini.ballNumber = 10
            qmlSignal("this is a qml signal")
        }
    }
    Gemini {
        id: gemini
        onBegin: doSomething(Gemini.BALL_COLOR_RED)
        onBallNumberChanged: console.log("new ball number is", ballNumber) // 10
        Component.onCompleted: console.log("default ball number is", ballNumber) // 0
    }
}

main.qml中添加了qmlSignal()信号和qmlFunction()函数,信号在QML中发送,函数在C++中调用。

(2)修改Gemini.h

#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include 
  
   
#include 
   
     class Gemini : public QObject { Q_OBJECT Q_ENUMS(BALL_COLOR) Q_PROPERTY(unsigned int ballNumber READ ballNumber WRITE setBallNumber NOTIFY ballNumberChanged) public: Gemini() : m_ballColor(BALL_COLOR_YELLOW), m_ballNumber(0) { qDebug() << "Gemini::Gemini() called"; } enum BALL_COLOR { BALL_COLOR_YELLOW, BALL_COLOR_RED, BALL_COLOR_BLUE, BALL_COLOR_ALL }; unsigned int ballNumber() const { return m_ballNumber; } void setBallNumber(const unsigned int &ballNumber) { if(ballNumber != m_ballNumber) { m_ballNumber = ballNumber; emit ballNumberChanged(); } } Q_INVOKABLE void stop() { qDebug() << "Gemini::stop() called"; } signals: void begin(); void ballNumberChanged(); public slots: void doSomething(BALL_COLOR ballColor) { qDebug() << "Gemini::doSomething() called with" << ballColor; if(ballColor != m_ballColor) { m_ballColor = ballColor; qDebug() << "ball color changed"; } } void cppSlot(const QString &message) { qDebug() << "Called the C++ slot with message:" << message; // this is a qml signal } private: BALL_COLOR m_ballColor; unsigned int m_ballNumber; }; #endif // GEMINI_H
   
  

Gemini类中添加了cppSlot()槽函数,将要在main.cpp中与QML的信号connect。

(3)修改main.cpp

#include 
  
   
#include 
   
     #include 
    
      int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType
     
      ("Union.Lotto.Gemini", 1, 0, "Gemini"); QQmlEngine engine; // set qml context property // Gemini aGemini; // engine.rootContext()->setContextProperty("aGemini", &aGemini); QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:///main.qml"))); QObject *object = component.create(); qDebug() << "width value is" << object->property("width").toInt(); object->setProperty("width", 500); qDebug() << "height value is" << QQmlProperty::read(object, "height").toInt(); QQmlProperty::write(object, "height", 500); QObject *rect = object->findChild
      
       ("rect"); if(rect) { rect->setProperty("color", "black"); } QVariant returnedValue; QVariant message = "Hello from C++"; QMetaObject::invokeMethod(object, "qmlFunction", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, message)); qDebug() << "returnedValue is" << returnedValue.toString(); // function from qml Gemini test; QObject::connect(object, SIGNAL(qmlSignal(QString)), &test, SLOT(cppSlot(QString))); return app.exec(); }
      
     
    
   
  

在main.cpp中添加了QMeta::invokeMethod()和QObject::connect()来分别访问QML中函数和信号。

7、总结

本文主要介绍了QML与C++混合编程常用的方法与技巧,在使用过程中有几点值得注意:

自定义类一定要派生自QObject类或其子类。

必须使用Q_OBJECT宏。

注册自定义类到Qt元对象系统或设置自定义类对象实例为QML上下文属性是必须的。

两者交互进行数据传递时,要符合QML与C++间数据类型的转换规则。