qml 组件化编程 MVC编程一

MVC编程,通俗的说就是实现数据、视图与业务的分离,采用分而治之的模式。也许很多人知道MVC是怎么回事,但是用起来却有点无从下手,那么我们先从小Deml说起。上代码

 

1、model与view分离,但是仍在qml中实现所有

import QtQuick 2.3

Rectange{
    width: 450
    height: 640;

    GridView{
        id: showView
        anchors.fill: parent
        cellWidth: 50
        cellHeight: 50
        
        model: dataModel
        delegate: delegateComp
    }

    Component{
        id: delegateComp
        Rectangle{
            width:  viewWidth
            height: viewHeight
            color:    itemColor
        }
    }

    ListModel{
        id: dateModel
        ListElement{viewWidth: 50; viewHeight: 50; itemColor: "red"}
        ListElement{viewWidth: 20; viewHeight: 50; itemColor: "yellow"}
        ListElement{viewWidth: 100; viewHeight: 100; itemColor: "blue"}    
    }    
}

效果图如下:

 

这里我们实现了一个最简单的MVC组件。但是从上图中效果有点费解,为什么设置了大小,却没起作用,甚至各个组件之间会有空白。这是因为GridView中cellWIdth决定的。如果组件的大小被cell的大小包含,那么cell比组件多出来的部分会用空白填充;反过来,如果组件的大小比cell大,那么就会被裁剪成cell大小,如蓝色框一般

 

 (1)现在我们在升级一部分功能,将小框组件化

//Rect.qml

import QtQuick 2.3
Rectangle{
}

//main.qml
import QtQuick 2.3
Rectange{
    width: 450
    height: 640;

    GridView{
        id: showView
        anchors.fill: parent
        cellWidth: 50
        cellHeight: 50
        
        model: dataModel
        delegate: delegateComp
    }

    Component{
        id: delegateComp
        Rect{
            width:  viewWidth
            height: viewHeight
            color:    itemColor
        }
    }

    ListModel{
        id: dateModel
        ListElement{viewWidth: 50; viewHeight: 50; itemColor: "red"}
        ListElement{viewWidth: 20; viewHeight: 50; itemColor: "yellow"}
        ListElement{viewWidth: 100; viewHeight: 100; itemColor: "blue"}    
    }    
}

我们通过把委托中的组件单独封装成一个独立的组件,这样不仅在这里可以使用,在其他地方也可以创建

(2)把Model从qml中剥离出来

 既然是组件化编程,那么数据是动态的,视图也是根据数据动态创建。而数据一般是由业务侧产生,业务侧我们由C++实现,这里先把业务动作隐藏,直接产生测试数据。

//ModelClass
class Apple{
public:
    Apple();
    Q_INVOKABLE QVariant getProperty();

private:
    int m_nWidth;
    int m_nHeight;
    QString m_strColor;
}

//main.cpp
int main()
{
  qmlRegisterType<Apple>("Model.Fruit", 1, 0, "Apple");
}

//main.qml
Rectanle{
    //MVC部分省略...

    Apple{
        id: appleObj
    }

    Component.onCompleted:{
        dateModel.append(appleObj.getProperty())
    }
}

在上面中,我们定义一个model类,用于产生数据,在适当的时机(比如创建组件完成后)把数据绑定到ListModel上。

同样,我们可以通过信号,当model类需要更新数据时,可以通过信号实现通知

 

(3)多层嵌套组件的数据透传

  上面只是一层的MVC,如果有多层的MVC,我们该如何把数据传到最底层呢?这就是本文章的最终说明,有一下几种方法

  1、C++侧根据数据,通过创建Component的方式加载qml,然后调用invokeMethod的方式将数据传过去

  2、qml采用MVC模式,C++侧实现Model,通过信号发送数据 

  3、model仍然在C++侧,但是qml中采用createComponent的方式创建。

  对于上面的几种方式,这里有几个关键的函数说明

  对于第一种,

QQmlEngine *pEngine = view.engine();
QQuickItem *pRootItem = view.rootObject()->findChild<QQuickItem*>("MainCanvas");

QQmlComponent comPont(pEngine, QUrl(QStringLiteral("qrc:;/test.qml")));
QQuickItem *pFirstItem = dynamic_cast<QQuickItem*>(comPont.create());
pFistItem->setParentItem(pRootItem);

QMetaObject::invokeMethod(pFirstItem, "onDraw", Q_ARG(QVariant, varFontInfo));

  对于第二和第三种,见源代码

 

posted @ 2019-08-15 14:05  Qt王二狗  阅读(1231)  评论(1)    收藏  举报