C++和QML混合编程

17 篇文章 1 订阅

QML中使用C++对象

官方文档:http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html

创建一个新类型

创建C++对象

piechart.h

#ifndef PIECHART_H
#define PIECHART_H
#include <QtQuick/QQuickPaintedItem>
#include <QColor>
#include <QPainter>

class PieChart : public QQuickPaintedItem
{
    //为了使用信号和槽系统和QML交互
    Q_OBJECT
    //Q_PROPERTY是QObject的宏定义,具体的含义可以去QObject中去查看
    //这里的意思是PieChart有一个属性name,获取属性的函数名是name,设置属性的函数名是setName
    Q_PROPERTY(QString name READ name WRITE setName)
    Q_PROPERTY(QColor color READ color WRITE setColor)
public:
    PieChart(QQuickItem *parent=0);
    QString name() const;
    void setName(const QString &name);
    QColor color() const;
    void setColor(const QColor &color);
    void paint(QPainter *painter);
private:
    QString myName;
    QColor myColor;
};

#endif // PIECHART_H

piechart.cpp

#include "piechart.h"
#include <QPainter>

PieChart::PieChart(QQuickItem *parent)
    :QQuickPaintedItem(parent)
{

}
QString PieChart::name() const
{
    return myName;
}
void PieChart::setName(const QString &name)
{
    myName = name;
}
QColor PieChart::color() const
{
    return myColor;
}
void PieChart::setColor(const QColor &color)
{
    myColor = color;
}
void PieChart::paint(QPainter *painter)
{
    QPen pen(myColor, 2);
    painter->setPen(pen);
    painter->setRenderHints(QPainter::Antialiasing, true);
    painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
}

将C++对象注册到QML中

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <piechart.h>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    //4个参数的含义是,包名,主版本号,此版本好,QML类型名
    qmlRegisterType<PieChart>("Charts",1,0,"PieChart");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    return app.exec();
}

在QML中使用C++注册到QML中的对象

main.qml

import QtQuick 2.7
import QtQuick.Controls 1.4
import Charts 1.0

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

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        name: "A simple pie chart"
        //这里自动转换为C++中的QColor类型
        color: "red"
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: aPieChart.name
    }
}

这里写图片描述
QML和C++数据类型转换
http://doc.qt.io/qt-5/qtqml-cppintegration-data.html

连接C++的方法和信号

点击控件,图形消失,并且在QML中处理chartCleared信号
piechart.h增加的代码

public:
    //将这个方法注册到元对象系统中,这样QML就能直接调用这个方法
    Q_INVOKABLE void clearChart();
signals:
    void chartCleared();

piechart.cpp增加的代码

void PieChart::clearChart()
{
    setColor(QColor(Qt::transparent));
    update();
    emit chartCleared();
}

main.qml的代码变为如下

import QtQuick 2.7
import QtQuick.Controls 1.4
import Charts 1.0

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

    PieChart {
         id: aPieChart
         anchors.centerIn: parent
         width: 100; height: 100
         color: "red"
         onChartCleared: console.log("The chart has been cleared")
     }

     MouseArea {
         anchors.fill: parent
         onClicked: aPieChart.clearChart()
     }

     Text {
         anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
         text: "Click anywhere to clear the chart"
     }
}

属性绑定

2个图形A和B,B的颜色就是A的颜色,点击整个控件,A的颜色变化,如果属性不绑定,就只有A的颜色发生变化,因为B不知道A的颜色发生变化,属性绑定后A和B的颜色会一起变化
piechart.h增加和修改的代码

//当color这个属性发生变化时,发送colorChanged这个信号,更新这个属性
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
signals:
    void colorChanged();

piechart.cpp修改的代码如下

void PieChart::setColor(const QColor &color)
{
    if (color != myColor)
    {
       myColor = color;
       update();   // repaint with the new color
       emit colorChanged();
    }
}

main.qml

import QtQuick 2.7
import QtQuick.Controls 1.4
import Charts 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    Row {
         anchors.centerIn: parent
         spacing: 20

         PieChart {
             id: chartA
             width: 100; height: 100
             color: "red"
         }

         PieChart {
             id: chartB
             width: 100; height: 100
             color: chartA.color
         }
     }

     MouseArea {
         anchors.fill: parent
         onClicked: { chartA.color = "blue" }
     }

     Text {
         anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
         text: "Click anywhere to change the chart color"
     }
}

这里写图片描述

使用自定义属性类型

C++中使用QML对象

官方文档:http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html

从C++中加载QML对象

按照官方文档写一直不对,也不知道问题出在哪里,就按照Qt Quick核心编程上的例子写了
通过C++改变QML文档中Item的宽度
main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    objectName: "window"
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Item {
        objectName: "item"
        width: 100
        height: 100

        Rectangle {
            anchors.fill: parent
            border.width: 1
        }
    }

}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QList>

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

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    QList<QObject*> rootObjects = engine.rootObjects();
    int count = rootObjects.size();
    QObject *root = NULL;
    for(int i=0; i<count; i++)
    {
        if(rootObjects.at(i)->objectName() == "window")
        {
            root = rootObjects.at(i);
            break;
        }
    }
    QObject *item = root->findChild<QObject*>("item");
    //判断是否是空指针
    if(item)
    {
        item->setProperty("width","200");
    }
    return app.exec();

}

QML中定义的是正方形,显示出来是长方形
这里写图片描述

从C++获取QML对象的成员

属性

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0


ApplicationWindow {
    objectName: "window"
    visible: true
    width: 640
    height: 480
    property int someNumber: 100
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QList>
#include <QDebug>

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

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    QList<QObject*> rootObjects = engine.rootObjects();
    int count = rootObjects.size();
    QObject *root = NULL;
    for(int i=0; i<count; i++)
    {
        if(rootObjects.at(i)->objectName() == "window")
        {
            root = rootObjects.at(i);
            break;
        }
    }
    qDebug() << "Property value:" << QQmlProperty::read(root, "someNumber").toInt();
    QQmlProperty::write(root, "someNumber", 5000);

    qDebug() << "Property value:" << root->property("someNumber").toInt();
    root->setProperty("someNumber", 100);
    return app.exec();

}

这里写图片描述

调用QML方法

在C++中调用QML中的方法
main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    objectName: "window"
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    function myQmlFunction(msg) {
        console.log("Got Message",msg)
        return "some return value"
    }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QDebug>
#include <QMetaObject>

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

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

    QList<QObject*> rootObjects = engine.rootObjects();
    int count = rootObjects.size();
    QObject *root = NULL;
    for(int i=0; i<count; i++)
    {
        if(rootObjects.at(i)->objectName() == "window")
        {
            root = rootObjects.at(i);
            break;
        }
    }
    QVariant returnedValue;
    QVariant msg = "Hello from C++";
    //参数含义:被调用对象的指针,方法名字,返回值,参数
    QMetaObject::invokeMethod(root, "myQmlFunction",
            Q_RETURN_ARG(QVariant, returnedValue),
            Q_ARG(QVariant, msg));

    qDebug() << "QML function returned:" << returnedValue.toString();
    //这个是运行完毕删除图形界面
    delete root;
    return app.exec();
}

这里写图片描述

连接QML的信号

在C++中接收QML中发出的信号
myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QDebug>
class MyClass : public QObject
{
    Q_OBJECT
public slots:
    void cppSlot(const QString &msg) {
        qDebug() << "Called the C++ slot with message:" << msg;
    }
};
#endif // MYCLASS_H

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QDebug>
#include <QMetaObject>
#include <myclass.h>
#include <QQuickView>
#include <QQuickItem>

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

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

    QList<QObject*> rootObjects = engine.rootObjects();
    int count = rootObjects.size();
    QObject *root = NULL;
    for(int i=0; i<count; i++)
    {
        if(rootObjects.at(i)->objectName() == "window")
        {
            root = rootObjects.at(i);
            break;
        }
    }
    MyClass myClass;
    QObject::connect(root, SIGNAL(qmlSignal(QString)),
                     &myClass, SLOT(cppSlot(QString)));
    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    objectName: "window"
    id: window
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    signal qmlSignal(string msg)

    MouseArea {
        anchors.fill: parent
        onClicked: window.qmlSignal("Hello from QML")
    }
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值