QML与C++混和编程

QML与C++混和编程

	在QT编程中界面开发往往是很重要的,界面也是乙方第一观感。
所以它的重要性不言而喻。一开始时我是用贴图来做界面,PPT做界
面是个不错的选择,后来想用QSS来做界面,QSS类似CSS,可以说是
CSS的一个简写版,但是我并没有学的太好,因为我一直想尝试下使
QML来做界面,主要是想法是QML做前端,C++来写后端,这也是现在
QT官方推荐的。硬着头皮学了几天,真的感觉到QML的强大与语言的
简洁高效,在与C++交叉编写时也认识到QT原对象系统的强大。
    向万能的Q_OBJECT致敬!

在QML中使用C++类

1、首先在cpp注册QML类型

//qmlRegisterType注册C++类型至QML
//arg1:import时模块名
//arg2:主版本号
//arg3:次版本号
//arg4:QML类型名
qmlRegisterType<Colors>("MyCppObject",1,0,"CppObject");

2、在QML文件中包含自定义QML类型

import MyCppObject 1.0

3、类要继承自Q_OBJECT

4、Q_PROPERTY属性说明

5、Q_INVOKABLE宏

#include <QObject>

class Colors : public QObject
{
    Q_OBJECT

    //注册属性,使之可以在QML中访问--具体语法请参考其他资料
    Q_PROPERTY(QString name READ getName WRITE setName)
    Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)

public:
    explicit Colors(QObject *parent = nullptr);

    //通过Q_INVOKABLE宏标记的public函数可以在QML中访问
    Q_INVOKABLE void sendSignal();//功能为发送信号

6、自定义属性Q_INVOKABLE宏说明

Q_PROPERTY(type name
   READ getFunction
   [WRITE setFunction]
   [RESET resetFunction]
   [NOTIFY notifySignal]
   [DESIGNABLE bool]
   [SCRIPTABLE bool]
   [STORED bool]
   [USER bool]
   [CONSTANT]
   [FINAL])
	   /*
	   下面是一些典型的声明属性的示例:
		Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue)
		Q_PROPERTY(bool animation READ getAnimation WRITE setAnimation)
		Q_PROPERTY(QColor barColor READ getBarColor WRITE setBarColor)
	  */
	  /*
		 Q_PROPERTY(类型名称
		读getFunction
		(写setFunction)
		(重置resetFunction)
		(通知notifySignal)
		(可被识别的bool)
		(脚本bool)
		(存储bool)
		(用户bool)
		(常量)
		[最终])
	  */

在C++中使用QML类

1、使用QQmlComponent创建QML对象

    QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/main.qml")));
    QObject* object = component.create();

    Colors *col = new Colors();
    QObject::connect(object, SIGNAL(qmlSignalA()),
                       col, SLOT(cppSlotmy()));

全部代码

//**ColorText.qml**
Item {
    id: root
    property string colorText //定义一个属性传递给外部
    property alias textFont1: text1.font //使用属性别名将内部的属性暴露给外部
    signal clicked(string buttonColor)   //定义一个信号 信号的第一个字母必须先写

    //动画持续时间函数
    function changeDuration(duration) {
        animation.duration = duration
        animation1.duration = duration/10
    }

    Text {
        id: text1
        text: colorText
        anchors.centerIn: parent
        Behavior on rotation {
            NumberAnimation {
                id: animation
                duration: 500
            }
        }
    }

    Rectangle {
        id: colorRect
        width: 20 * 2
        height: width
        //radius: 20
        border.color: "green"

        //锚点在text1的右边,距离为10,以text1的垂直剧中
        anchors.left: text1.right
        anchors.leftMargin: 10
        anchors.verticalCenter: text1.verticalCenter

        //定义一个默认是的行为动作
        Behavior on width {
            NumberAnimation {
                id: animation1
                duration: 50
            }
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                console.debug("colorRect: ", parent.border.color)
                text1.rotation += 360
                text1.color = parent.border.color
                root.clicked(parent.border.color)   //触发自定义的信号 并传入参数
            }

            hoverEnabled: true
            onEntered: {
                parent.width = 32
                parent.color = "black"
            }
            onExited: {
                parent.width = 40
                parent.color = "white"
            }
        }

        Rectangle {
            width: 12 * 2
            height: width
            radius: 12
            color: parent.border.color
            anchors.centerIn: parent
        }
    }

    Rectangle {
        id: colorRect2
        width: 20 * 2
        height: width
        radius: 20
        border.color: "red"

        //锚点在text1的右边,距离为10,以text1的垂直剧中
        anchors.bottom: text1.top
        anchors.bottomMargin: 10
        anchors.horizontalCenter: text1.horizontalCenter

        MouseArea {
            anchors.fill: parent
            onClicked: {
                console.debug("colorRect: ", parent.border.color)
                text1.rotation += 360
                text1.color = parent.border.color
                root.clicked(parent.border.color)
            }

            hoverEnabled: true
            onEntered: {
                parent.width = 32
                parent.color = "black"
            }
            onExited: {
                parent.width = 40
                parent.color = "white"
            }
        }

        Rectangle {
            width: 12 * 2
            height: width
            radius: 12
            color: parent.border.color
            anchors.centerIn: parent
        }
    }

    Rectangle {
        id: colorRect3
        width: 20 * 2
        height: width
        radius: 20
        border.color: "blue"

        //锚点在text1的右边,距离为10,以text1的垂直剧中
        anchors.right:  text1.left
        anchors.rightMargin: 10
        anchors.verticalCenter: text1.verticalCenter

        MouseArea {
            anchors.fill: parent

            onClicked: {
                console.debug("colorRect: ", parent.border.color)
                text1.rotation += 360
                text1.color = parent.border.color
                root.clicked(parent.border.color)
            }

            hoverEnabled: true
            onEntered: {
                parent.width = 32
                parent.color = "black"
            }
            onExited: {
                parent.width = 40
                parent.color = "white"
            }
        }

        Rectangle {
            width: 12 * 2
            height: width
            radius: 12
            color: parent.border.color
            anchors.centerIn: parent
        }
    }
}
import QtQuick 2.12
import QtQuick.Window 2.12
import MyCppObject 1.0

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

    signal qmlSignalA()
    signal qmlSignalB(string str,int value)

    Image {
        id: backImg
        source: "qrc:/img/press.png"
        width: parent.width
        height: parent.height
        anchors.bottom: parent.bottom
        fillMode: Image.PreserveAspectFit // 填充模式;缩放时保持比例
    }

    ColorText {
        anchors.centerIn: parent
        onClicked: {
            colorText = qsTr("我爱你!")

            console.log("colorButton: ", buttonColor)
            var value = buttonColor
            switch (value) {
            case "#ff0000":
                backImg.source = "qrc:/img/ok.jpg"
                  changeDuration(2000)
                break
            case "#0000ff":
                backImg.source = "qrc:/img/press.png"
                changeDuration(1000)
                break
            default:
                changeDuration(500)
                backImg.source = "qrc:/img/bg1.png"
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        //测试从点击开始
        //左键--Cpp发射信号
        //右键--Qml发射信号
        onClicked: {
            if(mouse.button===Qt.LeftButton){
                console.log('----clicked left button')
                cpp_obj.name="gongjianbo"
                cpp_obj.year=1992
                cpp_obj.sendSignal() //调用Q_INVOKABLE宏标记的函数
            }else{
                console.log('----clicked right button')
                root.qmlSignalA()
                root.qmlSignalB('0000',9999)
            }
        }
    }

    //作为一个QML对象
     CppObject{
         id:cpp_obj
         //也可以像原生QML对象一样操作
         property int counts: 0
//         onYearChanged: {
//             counts++
//             console.log('qml name changed process')
//         }
//         onCountsChanged: {
//             console.log('qml counts changed process')
//         }
     }

     Component.onCompleted: {
         //关联信号与信号处理函数的方式同QML中的类型
         //cpp object connect qml object
         cpp_obj.onCppSignalA.connect(function(){console.log('qml signal a process')})
         cpp_obj.onCppSignalB.connect(processB)
         //qml object connect cpp object
         root.onQmlSignalA.connect(cpp_obj.cppSlotA)
         root.onQmlSignalB.connect(cpp_obj.cppSlotB)
     }

     function processB(str,value) {
         console.log('qml signal b process',str,value)
     }

}

/*##^## Designer {
    D{i:1;anchors_height:78;anchors_width:172;anchors_x:274;anchors_y:584}D{i:2;anchors_height:578;anchors_width:308;anchors_x:64;anchors_y:390}
}
 ##^##*/


#ifndef COLORS_H
#define COLORS_H

#include <QObject>

class Colors : public QObject
{
    Q_OBJECT

    //注册属性,使之可以在QML中访问--具体语法请参考其他资料
    Q_PROPERTY(QString name READ getName WRITE setName)
    Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)

public:
    explicit Colors(QObject *parent = nullptr);

    //通过Q_INVOKABLE宏标记的public函数可以在QML中访问
    Q_INVOKABLE void sendSignal();//功能为发送信号

    //给类属性添加访问方法--myName
       void setName(const QString &name);
       QString getName() const;
       //给类属性添加访问方法--myYear
       void setYear(int year);
       int getYear() const;

signals:
      //信号可以在QML中访问
      void cppSignalA();//一个无参信号
      void cppSignalB(const QString &str,int value);//一个带参数信号
      void yearChanged(int year);

public slots:
      //public槽函数可以在QML中访问
      void cppSlotA();//一个无参槽函数
      void cppSlotmy();//一个无参信号
      void cppSlotB(const QString &str,int value);//一个带参数槽函数

private:
    //类的属性
    QString myName;
    int myYear;

};

#endif // COLORS_H

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "colors.h"
#include "QDebug"
#include "QQuickView"
#include "QObject"
#include <QQmlProperty>
#include <QQuickView>
#include <QQuickItem>
#include <QMetaObject>
#include "QQmlApplicationEngine"

#define cout qDebug()  << "[" <<__FILE__ <<":"<<__FUNCTION__<<":"<<__LINE__ <<"]"
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

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

    QGuiApplication app(argc, argv);

    //qmlRegisterType注册C++类型至QML
    //arg1:import时模块名
    //arg2:主版本号
    //arg3:次版本号
    //arg4:QML类型名
    qmlRegisterType<Colors>("MyCppObject",1,0,"CppObject");

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    QQuickView view(QUrl("qrc:/main.qml"));
    view.show();

    QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/main.qml")));
    QObject* object = component.create();

    Colors *col = new Colors();
    QObject::connect(object, SIGNAL(qmlSignalA()),
                       col, SLOT(cppSlotmy()));

    return app.exec();
}

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

Colors::Colors(QObject *parent) : QObject(parent)
{

}

void Colors::sendSignal()
{
    //测试用,调用该函数后发送信号
    qDebug()<<"cpp sendSignal method";
    emit cppSignalA();
    emit cppSignalB(myName,myYear);
}

void Colors::setName(const QString &name)
{
    qDebug()<<"cpp setName"<<name;
    myName=name;
}

QString Colors::getName() const
{
    qDebug()<<"cpp getName";
    return myName;
}

void Colors::setYear(int year)
{
    qDebug()<<"cpp setYear"<<year;
    if(year!=myYear){
        qDebug()<<"cpp emit yearChanged";
        myYear=year;
        emit yearChanged(myYear);
    }
}

int Colors::getYear() const
{
    qDebug()<<"cpp getYear";
    return myYear;
}

void Colors::cppSlotA()
{
    qDebug()<<"cpp slot a";
}

void Colors::cppSlotmy()
{
    qDebug()<<"AAAAAAAAAAAAAAAAAAAAAAAAAAA";
}

void Colors::cppSlotB(const QString &str, int value)
{
    qDebug()<<"cpp slot b"<<str<<value;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值