一、Model-View
1.1、Qt中的model-view是什么
有点类似MVC模式,Qt中,数据通过model-view模式,将数据和显示分离开来
model: 数据模型,负责存储和管理数据view: 视图容器,负责布局和显示管理delegate: 可视化代理,负责单个数据项的可视化呈现
1.2、有哪些view
常见视图组件:
ListView- 列表视图GridView- 网格视图TableView- 表格视图PathView- 路径视图Repeater- 重复器(非视图组件,但常用于重复创建项目)
1.3、Repeater
Repeater是Qt中一个非常有用的组件,它可以重复渲染一组数据。它类似于其他框架中的列表或表格控件,但它的灵活性更高,因为它可以处理任意类型的模型(如字符串、图像等)。
- 属性:
- count: 创建多少项
 - delegate: 每个项的渲染模板
 - model: 数据源
 
 - 信号:
- itemAdded(int index, Item item): 当一个新的项被添加到Repeater时发出。
- onItemAdded(int index, Item item): 处理信号
 
 - itemRemoved(int index, Item item): 当一个项被从Repeater中移除时发出。
- onItemRemoved: 处理信号
 
 
 - itemAdded(int index, Item item): 当一个新的项被添加到Repeater时发出。
 
注意:
Repeater通常会创建其所有delegate项;如果存在大量delegate项,并且并非所有项都必须同时可见,会降低效率,需要考虑其他view
示例代码:
            
            
              javascript
              
              
            
          
          import QtQuick 
Column{
    spacing:10
    Repeater{
        model: 5
        delegate: Rectangle{
            width: 100; height: 50
            color:"red"
        }
       onItemAdded: {
            console.log("item " + index + "added")
        }
        onItemRemoved: {
            console.log("item" + index + "removed")
        }
    }
}
        1.4、ListView
类似于Repaeter,只不过delegate之间有间隔,并且可以滑动,所谓的瀑布流布局
关键属性:
spacing: 项间距orientation: 布局方向(默认垂直)clip: 是否裁剪超出区域的内容cacheBuffer: 预渲染缓冲区大小currentIndex: 当前选中项索引highlight: 高亮组件
示例代码:
            
            
              javascript
              
              
            
          
          ListView{
    anchors.fill: parent
    anchors.margins: 20
    spacing: 15
    clip: true                  // 默认是false,设置为true,在视觉上,会看不见元素创建与销毁的过程
    model: 100
    cacheBuffer: 20             // 如果需要展示的元素过多,可以设置缓存区大小,节省频繁创建销毁的内存开销
    delegate: Rectangle{
        required property int index
        width: 20
        height: 25
        color: "red"
        Component.onCompleted: {
            console.log(index + " added")
        }
        Component.onDestruction: {
            console.log(index + " deleted")
        }
    }
}
        1.5、GridView
使用GridView可以创建网格布局,类似于ListView,只不过是将delegate布局成网格
关键属性:
cellWidth、cellHeight: 网格大小flow: 布局流向(FlowTopToBottom/FlowLeftToRight)layoutDirection: 布局方向(LeftToRight/RightToLeft)
示例代码:
            
            
              javascript
              
              
            
          
          GridView{
        anchors.fill: parent
        clip: true
        model:100
        cellWidth:40            // 设置每个小网格的长宽
        cellHeight:40
        flow:GridView.FlowTopToBottom   // 布局方式是从上到下
        //flow:GridView.FlowLeftToRight   // 布局方式是从左到右
        delegate: Rectangle{
            width: 20
            height: 20
            color: "red"
        }
}
        1.6、Delegete
delegate翻译过来是代理,委托的意识;在model-view中,delegate是介于数据和视图之间的桥梁
- 从model获取数据
 - 定义数据可视化方式
 - 响应视图状态变化
 
示例代码:
            
            
              javascript
              
              
            
          
              ListView{
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15
        clip: true                  // 默认是false,设置为true,在视觉上,会看不见元素创建与销毁的过程
        model: 100
        cacheBuffer: 20             // 如果需要展示的元素过多,可以设置缓存区大小,节省频繁创建销毁的内存开销
        delegate: numberDelegate
    }
    Component{
        id: numberDelegate
        Rectangle{
            required property int index
            width: 40
            height: 25
            color: ListView.isCurrentItem ? "black" : "red"
            id: wrapper
            Text{
                id:label1
                text: wrapper.index
                anchors.centerIn: parent
            }
        }
    }
        delegate动画- onAdd
 - onRemove
 
示例代码:
            
            
              javascript
              
              
            
          
          delegate: Rectangle {
    required property int index
        
    // 添加动画
    GridView.onAdd: SequentialAnimation {
        NumberAnimation { 
            property: "scale"; from: 0; to: 1; duration: 300 
        }
    }
    
    // 移除动画  
    GridView.onRemove: SequentialAnimation {
        NumberAnimation { 
            property: "scale"; to: 0; duration: 300 
        }
    }
}
        二、测试
场景:两个按钮,一个按钮点击,在网格中添加一个元素;另一个按钮点击,删除最后一个元素
            
            
              javascript
              
              
            
          
          import QtQuick
Rectangle{
    anchors.fill: parent
    gradient: Gradient{
        GradientStop{position:0.0; color:"#dbdbdb"}
        GradientStop{position:1.0; color:"#5fc9f8"}
    }
    // model
    ListModel{
        id:theModel
        ListElement{ num:0}
        ListElement{ num:1}
        ListElement{ num:2}
        ListElement{ num:3}
    }
    //button
    Rectangle{
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.margins: 20
        height: 40
        color: "#53f769"
        border.color: Qt.lighter(color, 1.1)
        Text{
            anchors.centerIn: parent
            text: qsTr("add")
        }
        MouseArea{
            anchors.fill: parent
            onClicked: {
                theModel.append({"num": theModel.count})
                console.log(theModel.count)
            }
        }
    }
    // 删除按钮
    Rectangle{
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.margins: 20
        anchors.bottomMargin: 60  // 在添加按钮上方
        height: 40
        color: "#f75353"
        border.color: Qt.lighter(color, 1.1)
        Text{
            anchors.centerIn: parent
            text: qsTr("remove last")
        }
        MouseArea{
            anchors.fill: parent
            onClicked: {
                if (theModel.count > 0) {
                    theModel.remove(theModel.count - 1)
                    console.log(theModel.count)
                }
            }
        }
    }
    // view
    GridView{
        anchors.fill: parent
        anchors.margins: 20
        anchors.bottomMargin: 80
        clip: true
        cellHeight: 40
        cellWidth: 60
        model:theModel
        delegate: numberDelegate
    }
    // Delegate
    Component{
        id: numberDelegate
        Rectangle{
            id: wrapper
            required property int index
            required property int num
            gradient: Gradient{
                GradientStop{position:0.0; color:"#dbdbdb"}
                GradientStop{position:1.0; color:"#5fc9f8"}
            }
            width: 40
            height: 25
            color: ListView.isCurrentItem ? "black" : "red"
            Text{
                id:label1
                text: qsTr(wrapper.index)
                anchors.centerIn: parent
            }
            // 添加动画
            GridView.onAdd:addAnimation.start()
            GridView.onRemove:removeAnimation.start()
            NumberAnimation{
                id:addAnimation
                target:wrapper
                property: "scale"
                from: 0
                to:1
                duration: 250
                easing.type: Easing.InOutQuad
            }
            NumberAnimation{
                id:removeAnimation
                target:wrapper
                property: "scale"
                to:0
                duration: 250
                easing.type: Easing.InOutQuad
            }
        }
    }
}
        