Qt QML自定义LIstView

news2025/5/10 12:53:22

QML ListView组合拳做列表,代码不可直接复制使用,需要小改

  • 先上图看效果
    • · 样式1
    • · 样式2
    • · 样式3
  • 原理:
  • 操作:
  • 技术点:
  • 代码片段:

先上图看效果

· 样式1

wu
三个表格组合成要给,上下滚动时,三个同时滚动,表格2可以左右滚动展示数据,三个表格每一列都可以自定义宽度,列的内容样式(文本、单个按钮、多个按钮、单选框)

· 样式2

在这里插入图片描述
两个表格组合,左侧可以拖动

· 样式3

在这里插入图片描述
正常一个表格,没有组合

原理:

通过三个ListView组合起来,左侧的ListView完全显示,右侧的ListView也完全展示,中间的通过width以及contentWidth实现拖动

操作:

  1. 设置itemWidthDic,通过下标控制每一列的宽度
  2. 设置titleKeyList 给标题赋值
  3. 设置itemTypeDic,控制数据项具体哪一列展示什么样式
  4. 设置itemTitleTypeDic,控制标题具体哪一列展示什么样式
  5. 设置middleItemBeginIndex设置中间列表从哪个下标开始
  6. 设置rightItemBeginIndex设置右侧列表从哪个下标开始。同第四点都设置为0则为效果3。middleItemBeginIndex设置为0,rightItemBeginIndex大于0则为效果2。都设置大于0则为效果1
  7. 设置onXXXXXXXXX信号,则可以监听具体的事件
  8. 重写getIsCheckByCR getTextObjComColor这些函数可以设置具体的数据列
  9. 监听onOnListMoving 对 视野距离进行判断 Math.abs(totalHeight - Math.abs(contentY)) <= viewHeight * 1.5 距离底部小于1.5倍视野时可以继续请求数据等等,实现滚动加载数据
  10. 设置其他项可以控制是否有列的分割线、标题、内容的透明度,标题是否有灰色背景等等

技术点:

  1. 每个控件类型都是Component组件,使用Loader动态加载组件,已Item作为父节点,让Item充满整个列宽度,Item受到外部约束。具体的Button Text 之类的组件作为子节点可以控制样式,因此外部Loader传递给每个组件的参数均一致,具体的组件按需使用
  2. 通过每一个ListViewonContentYChanged,结合!rightData.moving && !leftData.moving 属性,让列表一起滚动时,不会出现中间列表控制其他一起滚动,其他列表又反过来作用中间列表的情况

代码片段:

注意项:代码不可直接粘贴使用,TextObj,CheckButton之类的组件都是封装过的,TextObj封装了Text, CheckButton 则是勾选按钮,需要自己重写样式即可需要改动的都在Component里面,其他的按照自己的需求继续扩写

import QtQuick 2.15
import QtQuick.Controls 2.15
// import QtQuick.Controls 1.4
// import QtGraphicalEffects 1.15
import QtQuick.Layouts 1.15

//暂时只设置左右两个列表,不设置左中右三个列表, 右侧列表完全展示
//2023/04/23日补充左边列表,共左中右三列,左列完全展示,右侧完全展示
Item {
    width: 1184
    height: 444
    // property var totalWidth: 1184
    //当自动设置autoItemWidth,itemWidth失效,minItemWidth始终生效,可以通过设置itemWidthDic指定宽度
    property var itemWidth: 200
    property var minItemWidth: 200
    property var itemWidthDic: ({})
    //列类型
    property var itemTypeDic: ({})
    //标题列类型
    property var itemTitleTypeDic: ({})

    property var autoItemWidth: false
    //两边的边距
    property var leftRightMargin: 24
    //是否显示竖条
    property var needSplitLine: false
    //是否标题灰底
    property var needTitleGrayColor: false
    //标题透明度
    property var titleTextComOpacity: 0.4
    property var contentTextComOpacity: 0.8
    //数据
    property var itemDataList: []
    property var titleKeyList: []
    property var titleKeyReplaceDic: ({})
    //已这个下标开始往后,认定为在右侧列表里面, 设置为0时,左侧列表消失,完全展示右侧列表
    property var rightItemBeginIndex: 0
    //同理上面参数,小于middleItemBeginIndex为左侧,大于等于middleItemBeginIndex,小于rightItemBeginIndex为中间
    property var middleItemBeginIndex: 0
    property alias listViewOfData: rightData
    property var alignDic: ({})
    //信号=============================
    signal onClickButtonObj(var index)
    signal onClick2ButtonObj(var cIndex, var rIndex, var num)
    //当高度发生类似光滑渐变时,派发高度变化的信号(表示列表正在滚动,而不是外界设置高度发生骤变)
    signal onListMoving(var contentY, var totalHeight, var viewHeight)
    signal onClickRadioButtonObj(var cIndex, var rIndex, var isTitle, bool isOn)
    //上滑返回true,下滑返回false
    signal onFlickTopOrBottom(bool isToBottom)
    //================================
    //private
    property var everyKeyWidth: 0
    //列枚举类型类型
    property int rowTextObj: 0
    property int columnRowTextObj: 1
    property int columnRowButton: 2
    property int columnRowRadio: 3
    property int columnRow2Button: 4
    property var keyOfItemType: ({})

    function update()
    {
        keyOfItemType[columnRowTextObj] = textObjCom
        // keyOfItemType[columnRowTextObj] = textObjCom1
        keyOfItemType[columnRowButton] = buttonObjCom
        keyOfItemType[columnRowRadio] = radioBtn
        keyOfItemType[columnRow2Button] = twoButtonObjCom

        let totalKeyCount = 0
        let leftWidth = width - leftRightMargin * 2

        //计算之前去掉已经固定宽度的列表
        for(let i = 0; i < titleKeyList.length; i++)
        {
            if(!itemWidthDic.hasOwnProperty(i))
            {
                totalKeyCount += titleKeyList[i].length
            }
            else
            {
                leftWidth -= itemWidthDic[i]
            }
        }
        console.log("宽度", titleKeyList, totalKeyCount)
        if(totalKeyCount == 0)
        {
            return
        }
        everyKeyWidth = (leftWidth / totalKeyCount).toFixed(2)
        //
        let rightTitleWidth = 0
        let middleTitleWidth = 0
        let leftTitleWidth = 0
        for(let i = 0; i < titleKeyList.length; i++)
        {
            if(i >= rightItemBeginIndex)
            {
                rightTitleWidth += getRowWidthByIndex(i)
            }
            else if(i >= middleItemBeginIndex && i < rightItemBeginIndex)
            {
                middleTitleWidth += getRowWidthByIndex(i)
            }
            else
            {
                leftTitleWidth += getRowWidthByIndex(i)
            }
        }
        rightFilckableItem.width = Math.min(rightTitleWidth, width - leftRightMargin * 2)
        rightFilckableItem.contentWidth = rightTitleWidth
        middleFilckableItem.width = width - leftRightMargin * 2 - rightTitleWidth - leftTitleWidth
        middleFilckableItem.contentWidth = middleTitleWidth
        leftFilckableItem.width = Math.min(leftTitleWidth, width - leftRightMargin * 2)
        leftFilckableItem.contentWidth = leftTitleWidth
        // middleTitle.width = width - leftRightMargin * 2 - rightTitleWidth//middleTitleWidth
        rightTitle.width = rightTitleWidth
        middleTitle.width = middleTitleWidth
        leftTitle.width = leftTitleWidth

        console.log("宽度1", leftWidth, totalKeyCount, rightTitleWidth, middleTitleWidth, titleKeyList.length - rightItemBeginIndex, rightItemBeginIndex, itemDataList.length)
        // rightTitleModel.clear()
        // rightTitleModel.append(new Array(titleKeyList.length - rightItemBeginIndex))
        rightTitle.model = getRightRowCount()
        middleTitle.model = getMiddleRowCount()
        leftTitle.model = getLeftRowCount()

        middleData.model = itemDataList.length
        rightData.model = itemDataList.length
        leftData.model = itemDataList.length

        // tableModel.appendRow({display: "name"})
        // tableModel.appendRow({display: "sex"})
        // tableModel.appendRow({display: "id"})
        // let TableModelColumn
        // console.log(tableView.columns)
        // console.log(tableModel.columnCount())
        // console.log()
        // tableModel.colums
    }

    function getRowWidthByIndex(index)
    {
        if(itemWidthDic.hasOwnProperty(index))
        {
            return itemWidthDic[index]
        }
        if(autoItemWidth == false)
        {
            return itemWidth
        }
        // console.log("计算宽度", index, everyKeyWidth, titleKeyList[index].length, itemWidthDic[index], itemWidth)
        //不是固定宽度,也不是自己设置,通过everyKeyWidth来计算
        return Math.max(everyKeyWidth * titleKeyList[index].length, minItemWidth)
    }

    function getMiddleRowCount()
    {
        return rightItemBeginIndex - middleItemBeginIndex
    }
    function getRightRowCount()
    {
        return titleKeyList.length - rightItemBeginIndex
    }
    function getLeftRowCount()
    {
        return middleItemBeginIndex
    }

    function getDataByColumAndRow(colum, row)
    {
        // console.log("数据个hi", titleKeyList[row], itemDataList[colum], itemDataList[colum][titleKeyList[row]])
        let test = {}
        // if(test.hasOwnProperty())
        let answer = ""
        if(itemDataList[colum] == undefined)
        {
            return ""
        }

        if(itemDataList[colum].hasOwnProperty(titleKeyList[row]))
        {
            answer = itemDataList[colum][titleKeyList[row]]
        }
        else
        {
            answer = itemDataList[colum][row]
        }
        // let returnData = itemDataList[colum][titleKeyList[row]]
        return answer == undefined ? "" : answer
    }

    function getTitleKeyReplaceKey(index, raw = true)
    {
        let key = titleKeyList[index]
        if(raw || !titleKeyReplaceDic.hasOwnProperty(key))
        {
            return key
        }
        return titleKeyReplaceDic[key]
    }

    function getItemTypeByIndex(index)
    {
        if(itemTypeDic.hasOwnProperty(index))
        {
            return keyOfItemType[itemTypeDic[index]]
        }
        return textObjCom
    }

    //标题控件哦~哦!哦~~
    function getTitleTypeByIndex(index)
    {
        if(itemTitleTypeDic.hasOwnProperty(index))
        {
            return keyOfItemType[itemTitleTypeDic[index]]
        }
        return textObjCom
    }

    //==================== 外部可以重写的接口 ================
    //从外部获取的设置项
    function getIsCheckByCR(c, r, isTitle)
    {
        return false
    }

    function getTextObjComColor(c, r, isTitle)
    {
        return "#FFFFFFFF"
    }

    //=====================================================

    function getCurTopShowIndex()
    {
        let mY = middleData.contentY
        let topIndex = Math.ceil(mY / 48)
        return topIndex
    }

    function getCurBottomShowIndex()
    {
        let mY = middleData.contentY + middleData.height
        let topIndex = Math.ceil(mY / 48)
        return topIndex
    }
    //跳转到具体的下标
    function jumpToIndex(index)
    {
        let cY = index * 48
        let newCY = Math.max(0, Math.min(cY, middleData.contentHeight - middleData.height))
        // console.log("硬控???", middleData.contentY, cY, newCY)
        middleData.contentY = newCY
    }
    //删除具体的下标
    function deleteIndex(index)
    {
        itemDataList.splice(index, 1)
        middleData.model = itemDataList.length
        rightData.model = itemDataList.length
        leftData.model = itemDataList.length
    }
    //刷新界面
    function updateListView()
    {
        let middleContentY = middleData.contentY
        middleData.contentY = 0
        rightData.contentY = 0
        leftData.contentY = 0

        middleData.model = 0
        rightData.model = 0
        leftData.model = 0
        middleData.model = itemDataList.length
        rightData.model = itemDataList.length
        leftData.model = itemDataList.length

        middleData.contentY = middleContentY
        rightData.contentY = middleContentY
        leftData.contentY = middleContentY
    }

    Rectangle{
       anchors.fill: parent
       color: "#05FFFFFF"
       radius: 4
       border.width: 2
       border.color: "#1AFFFFFF"

       Rectangle{
           width: parent.width - 4
           anchors.left: parent.left
           anchors.leftMargin: 2
           anchors.top: parent.top
           anchors.topMargin: 50
           height: 2
           color: "#1AFFFFFF"
       }
    }

    Component{
        id: textObjCom
        Item{
            property int rIndex: parent.rIndex != undefined ? parent.rIndex : 0
            property int cIndex: parent.cIndex != undefined ? parent.cIndex : 0
            property real comOpacity: parent.comOpacity != undefined ? parent.comOpacity : 0
            property bool isTitleText: parent.isTitle != undefined ? parent.isTitle : true

            TextObj{
                label: parent.isTitleText ? getTitleKeyReplaceKey(parent.rIndex, false) : getDataByColumAndRow(parent.cIndex, parent.rIndex)
                width: parent.width - 32
                height: parent.height
                anchors.left: parent.left
                anchors.leftMargin: 16
                horizontalAlignment: alignDic.hasOwnProperty(parent.rIndex) ? alignDic[parent.rIndex] : Text.AlignLeft
                maximumLineCount: 2
                color: getTextObjComColor(cIndex, rIndex, isTitle)
                wrapMode: Text.WordWrap
                opacity: parent.comOpacity
            }
        }

    }

    Component{
        id: buttonObjCom

        Item{
            id: buttonObjComItem
            property int rIndex: parent.rIndex != undefined ? parent.rIndex : 0
            property int cIndex: parent.cIndex != undefined ? parent.cIndex : 0
            property real comOpacity: parent.comOpacity != undefined ? parent.comOpacity : 0
            // opacity: 0.2

            Button{
                width: 69
                height: 32

                background: Rectangle{
                    color: "transparent"
                    border.color: "#33FFFFFF"
                    border.width: 2
                    radius: 4
                }

                TextObj{
                    anchors.fill: parent
                    label: "详情"
                }
                // anchors.centerIn: parent
                anchors.right: parent.right
                anchors.rightMargin: 8
                anchors.verticalCenter: parent.verticalCenter

                MouseArea{
                    anchors.fill: parent
                    onClicked: {
                        console.log("点击下标", buttonObjComItem.cIndex)
                        // onClickDetail(buttonObjComItem.cIndex)
                        onClickButtonObj(buttonObjComItem.cIndex)
                    }
                }
            }
        }
    }

    Component{
        id: radioBtn

        Item{
            id: radioBtnComItem
            property int rIndex: parent.rIndex != undefined ? parent.rIndex : 0
            property int cIndex: parent.cIndex != undefined ? parent.cIndex : 0
            property real comOpacity: parent.comOpacity != undefined ? parent.comOpacity : 0
            property bool isTitle: parent.isTitle != undefined ? parent.isTitle : true
            // opacity: 0.2

            CheckButton{
                width: 24
                height: 24

                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
                checked: getIsCheckByCR(cIndex, rIndex, isTitle)

                onClicked: {
                    onClickRadioButtonObj(cIndex, rIndex, isTitle, isOn)
                }
            }
        }
    }

    Component{
        id: twoButtonObjCom

        Item{
            id: twoButtonObjComItem
            property int rIndex: parent.rIndex != undefined ? parent.rIndex : 0
            property int cIndex: parent.cIndex != undefined ? parent.cIndex : 0
            property real comOpacity: parent.comOpacity != undefined ? parent.comOpacity : 0
            // opacity: 0.2

            ButtonCancel{
                id: button1
                width: 69
                height: 32
                labelTxt: "View"
                // anchors.centerIn: parent
                anchors.right: parent.right
                anchors.rightMargin: (parent.width - (69 + 69 + 16)) / 2
                anchors.verticalCenter: parent.verticalCenter

                onClicked: {
                    onClick2ButtonObj(cIndex, rIndex, 1)
                }
            }

            ButtonCancel{
                id: button2
                width: 69
                height: 32
                labelTxt: "Delete"
                // anchors.centerIn: parent
                anchors.right: button1.left
                anchors.rightMargin: 16
                anchors.verticalCenter: parent.verticalCenter

                onClicked: {
                    onClick2ButtonObj(cIndex, rIndex, 2)
                }
            }
        }
    }
	//右侧阴影条效果
    Rectangle{
        id: markItem
        width: 16
        height: rightFilckableItem.height - 4// - middleTitle.height
        anchors.top: parent.top
        anchors.topMargin: 2
        anchors.right: rightFilckableItem.left
        anchors.rightMargin: 0
        // 定义线性渐变
        gradient: Gradient {
            orientation: Gradient.Horizontal
            // GradientStop { position: 0.0; color: "#2196F3" } // 起始颜色(蓝色)
            // GradientStop { position: 1.0; color: "#4CAF50" } // 结束颜色(绿色)
            GradientStop { position: 0.0; color: "#01000000" } // 起始颜色(蓝色)
            GradientStop { position: 1.0; color: "#1A000000" } // 结束颜色(绿色)
        }
        visible: rightItemBeginIndex > 0
    }

    //右侧东西
    Flickable {
        id: rightFilckableItem
        width: 0
        height: parent.height// - middleTitle.height
        anchors.top: parent.top
        anchors.topMargin: 0
        anchors.right: parent.right
        anchors.rightMargin: leftRightMargin
        contentWidth: 0
        clip: true

        ListView{
            id: rightTitle
            width: 0
            height: 50
            anchors.top: parent.top
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            orientation: ListView.Horizontal
            clip: true
            model: 0

            delegate: Item{
                property var dataIndex: rightItemBeginIndex + index
                width: getRowWidthByIndex(dataIndex)
                height: rightTitle.height
                Rectangle{
                    anchors.fill: parent
                    color: "#0DFFFFFF"
                    visible: needTitleGrayColor
                }

                Rectangle{
                    width: 2
                    height: parent.height - 2
                    color: "#1AFFFFFF"
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: 2
                    visible: needSplitLine && dataIndex != 0
                }

                // 动态加载组件
                Loader {
                    id: loader
                    // 根据模型中的type字段决定加载哪个组件
                    // anchors.fill: parent
                    width: parent.width
                    height: parent.height
                    sourceComponent: getTitleTypeByIndex(dataIndex)
                    // 将模型数据传递给子组件
                    property int rIndex: dataIndex
                    property real comOpacity: titleTextComOpacity
                    property bool isTitle: true
                }
            }
            interactive: false
        }

        ListView{
            id: rightData
            width: rightTitle.width
            height: parent.height - rightTitle.height
            anchors.top: rightTitle.bottom
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            clip: true
            model: 0

            delegate: Item{
                //行
                property var dataCIndex: index
                width: rightFilckableItem.contentWidth
                height: 48
                ListView{
                    id: rightDataItem
                    width: rightFilckableItem.contentWidth
                    height: 48
                    orientation: ListView.Horizontal
                    clip: true
                    model: getRightRowCount()

                    delegate: Item{
                        property var dataRIndex: rightItemBeginIndex + index
                        width: getRowWidthByIndex(dataRIndex)
                        height: rightDataItem.height

                        Rectangle{
                            width: 2
                            height: parent.height - 2
                            color: "#1AFFFFFF"
                            anchors.left: parent.left
                            anchors.leftMargin: 0
                            anchors.top: parent.top
                            anchors.topMargin: 0
                            visible: needSplitLine && dataRIndex != 0
                        }

                        Loader {
                            id: loader1
                            width: parent.width
                            height: parent.height
                            // 根据模型中的type字段决定加载哪个组件
                            sourceComponent: getItemTypeByIndex(dataRIndex)
                            // 将模型数据传递给子组件
                            property int rIndex: dataRIndex
                            property int cIndex: dataCIndex
                            property real comOpacity: contentTextComOpacity
                            property bool isTitle: false
                        }
                    }

                    interactive: false
                }

                Rectangle{
                    width: parent.width
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.bottom: parent.bottom
                    anchors.bottomMargin: 0
                    height: 2
                    color: "#1AFFFFFF"
                }
            }

            onFlickStarted: {
                console.log("##########. " + contentY)
            }

            onFlickEnded: {
                if(verticalVelocity <= 0)
                {
                    onFlickTopOrBottom(true)
                }
                else
                {
                    onFlickTopOrBottom(false)
                }
            }
            onContentYChanged: {
                if (!middleData.moving && !leftData.moving) {
                    middleData.contentY = contentY
                    leftData.contentY = contentY
                }
            }
            // onContentYChanged: {
            //     middleData.contentY = contentY
            // }
        }
    }

    //中间列表
    Flickable {
        id: middleFilckableItem
        width: 0
        height: parent.height// - middleTitle.height
        anchors.top: parent.top
        anchors.topMargin: 0
        anchors.right: rightFilckableItem.left
        anchors.rightMargin: 0
        contentWidth: 0
        clip: true
        boundsBehavior: Flickable.StopAtBounds

        ListView{
            id: middleTitle
            width: 0
            height: 50
            anchors.top: parent.top
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            orientation: ListView.Horizontal
            clip: true
            model: 0

            delegate: Item{
                property var dataIndex: middleItemBeginIndex + index
                width: getRowWidthByIndex(dataIndex)
                height: rightTitle.height
                Rectangle{
                    anchors.fill: parent
                    color: "#0DFFFFFF"
                    visible: needTitleGrayColor
                }

                Rectangle{
                    width: 2
                    height: parent.height - 2
                    color: "#1AFFFFFF"
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: 2
                    visible: needSplitLine && dataIndex != 0
                }
                // 动态加载组件
                Loader {
                    id: loader2
                    width: parent.width
                    height: parent.height
                    sourceComponent: getTitleTypeByIndex(dataIndex)
                    // 将模型数据传递给子组件
                    property int rIndex: dataIndex
                    property real comOpacity: titleTextComOpacity
                    property bool isTitle: true
                }
            }
            interactive: false
        }

        ListView{
            id: middleData
            width: middleTitle.width
            height: parent.height - middleTitle.height
            anchors.top: middleTitle.bottom
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            clip: true
            model: 0

            delegate: Item{
                //行
                property var dataCIndex: index
                width: middleFilckableItem.contentWidth
                height: 48
                ListView{
                    id: middleDataItem
                    width: middleFilckableItem.contentWidth
                    height: 48
                    orientation: ListView.Horizontal
                    clip: true
                    model: getMiddleRowCount()

                    delegate: Item{
                        property var dataRIndex: middleItemBeginIndex + index
                        width: getRowWidthByIndex(dataRIndex)
                        height: middleDataItem.height

                        Rectangle{
                            width: 2
                            height: parent.height - 2
                            color: "#1AFFFFFF"
                            anchors.left: parent.left
                            anchors.leftMargin: 0
                            anchors.top: parent.top
                            anchors.topMargin: 0
                            visible: needSplitLine && dataRIndex != 0
                        }

                        Loader {
                            id: loader4
                            width: parent.width
                            height: parent.height
                            // 根据模型中的type字段决定加载哪个组件
                            sourceComponent: getItemTypeByIndex(dataRIndex)
                            // 将模型数据传递给子组件
                            property int rIndex: dataRIndex
                            property int cIndex: dataCIndex
                            property real comOpacity: contentTextComOpacity
                            property bool isTitle: false
                        }
                    }

                    interactive: false
                }

                Rectangle{
                    width: parent.width
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.bottom: parent.bottom
                    anchors.bottomMargin: 0
                    height: 2
                    color: "#1AFFFFFF"
                }
            }

            onFlickStarted: {
                console.log("##########. " + contentY)
            }

            onMovingChanged: {
                if(moving == false)
                {
                    middleData.listSuddentlyChange = false
                }
            }

            onFlickEnded: {
                if(verticalVelocity <= 0)
                {
                    onFlickTopOrBottom(true)
                }
                else
                {
                    onFlickTopOrBottom(false)
                }
            }
            onContentYChanged: {
                if (!rightData.moving && !leftData.moving) {
                    rightData.contentY = contentY
                    leftData.contentY = contentY
                }
                onListMoving(contentY, contentHeight, height)
                // console.log("高度发生了改变", contentY, contentHeight)
            }

            // onContentYChanged: {
            //     rightData.contentY = contentY
            // }
        }
    }

    //左侧东西
    Flickable {
        id: leftFilckableItem
        width: 0
        height: parent.height// - middleTitle.height
        anchors.top: parent.top
        anchors.topMargin: 0
        anchors.right: middleFilckableItem.left
        anchors.rightMargin: 0
        contentWidth: 0
        clip: true

        ListView{
            id: leftTitle
            width: 0
            height: 50
            anchors.top: parent.top
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            orientation: ListView.Horizontal
            clip: true
            model: 0

            delegate: Item{
                property var dataIndex: index
                width: getRowWidthByIndex(dataIndex)
                height: rightTitle.height
                Rectangle{
                    anchors.fill: parent
                    color: "#0DFFFFFF"
                    visible: needTitleGrayColor
                }

                Rectangle{
                    width: 2
                    height: parent.height - 2
                    color: "#1AFFFFFF"
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: 2
                    visible: needSplitLine && dataIndex != 0
                }
                // 动态加载组件
                Loader {
                    id: leftLoader
                    // 根据模型中的type字段决定加载哪个组件
                    // anchors.fill: parent
                    width: parent.width
                    height: parent.height
                    sourceComponent: getTitleTypeByIndex(dataIndex)
                    // 将模型数据传递给子组件
                    property int rIndex: dataIndex
                    property real comOpacity: titleTextComOpacity
                    property bool isTitle: true
                }
            }
            interactive: false
        }

        ListView{
            id: leftData
            width: leftTitle.width
            height: parent.height - leftTitle.height
            anchors.top: leftTitle.bottom
            anchors.topMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 0
            clip: true
            model: 0

            delegate: Item{
                //行
                property var dataCIndex: index
                width: leftFilckableItem.contentWidth
                height: 48
                ListView{
                    id: leftDataItem
                    width: leftFilckableItem.contentWidth
                    height: 48
                    orientation: ListView.Horizontal
                    clip: true
                    model: getRightRowCount()

                    delegate: Item{
                        property var dataRIndex: index
                        width: getRowWidthByIndex(dataRIndex)
                        height: leftDataItem.height

                        Rectangle{
                            width: 2
                            height: parent.height - 2
                            color: "#1AFFFFFF"
                            anchors.left: parent.left
                            anchors.leftMargin: 0
                            anchors.top: parent.top
                            anchors.topMargin: 0
                            visible: needSplitLine && dataRIndex != 0
                        }

                        Loader {
                            id: loader13
                            width: parent.width
                            height: parent.height
                            // 根据模型中的type字段决定加载哪个组件
                            sourceComponent: getItemTypeByIndex(dataRIndex)
                            // 将模型数据传递给子组件
                            property int rIndex: dataRIndex
                            property int cIndex: dataCIndex
                            property real comOpacity: contentTextComOpacity
                            property bool isTitle: false
                        }
                    }

                    interactive: false
                }

                Rectangle{
                    width: parent.width
                    anchors.left: parent.left
                    anchors.leftMargin: 0
                    anchors.bottom: parent.bottom
                    anchors.bottomMargin: 0
                    height: 2
                    color: "#1AFFFFFF"
                }
            }

            onFlickStarted: {
                console.log("##########. " + contentY)
                // selectListview.contentY = contentY
                // movePos = contentY
            }

            onFlickEnded: {
                if(verticalVelocity <= 0)
                {
                    onFlickTopOrBottom(true)
                }
                else
                {
                    onFlickTopOrBottom(false)
                }
            }
            onContentYChanged: {
                if (!middleData.moving && !rightData.moving) {
                    middleData.contentY = contentY
                    rightData.contentY = contentY
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++进阶--红黑树的实现

文章目录 红黑树的实现红黑树的概念红黑树的规则红黑树的效率 红黑树的实现红黑树的结构红黑树的插入变色单旋&#xff08;变色&#xff09;双旋&#xff08;变色&#xff09; 红黑树的查找红黑树的验证 总结&#xff1a;结语 很高兴和大家见面&#xff0c;给生活加点impetus&a…

WPF之值转换器

文章目录 目录什么是值转换器IValueConverter接口Convert方法ConvertBack方法 创建和使用值转换器定义转换器类在XAML中使用转换器转换器参数&#xff08;ConverterParameter&#xff09; 常用转换器实现布尔值转可见性&#xff08;BoolToVisibilityConverter&#xff09;数值转…

qml中的TextArea使用QSyntaxHighlighter显示高亮语法

效果图&#xff0c;左侧显示行号&#xff0c;右侧用TextArea显示文本内容&#xff0c;并且语法高亮。 2025年5月8号更新 1、多行文本注释 多行文本注释跟普通的高亮规则代码不太一样&#xff0c;代码需要修改&#xff0c;这里以JavaScript举例。 先制定多行文本注释规则&…

Transformer编码器+SHAP分析,模型可解释创新表达!

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基本介绍 基于SHAP分析的特征选择和贡献度计算&#xff0c;Matlab2023b代码实现&#xff1b;基于MATLAB的SHAP可解释Transformer编码器回归模型&#xff0c;敏感性分析方法。 详细介绍 引言 在正向渗透&#xff08…

[特殊字符]适合母亲节的SVG模版[特殊字符]

宝藏模版 往期推荐&#xff08;点击阅读&#xff09;&#xff1a; 趣味效果&#xff5c;高大上&#xff5c;可爱风&#xff5c;年终总结I&#xff5c;年终总结II&#xff5c;循环特效&#xff5c;情人节I&#xff5c;情人节II&#xff5c;情人节IIII&#xff5c;妇女节I&…

浅蓝色调风格人像自拍Lr调色预设,手机滤镜PS+Lightroom预设下载!

调色教程 浅蓝色调风格人像自拍 Lr 调色是利用 Adobe Lightroom 软件针对人像自拍照进行后期处理的一种调色方式。它通过对照片的色彩、对比度、亮度等参数进行精细调整&#xff0c;将画面的主色调打造为清新、柔和的浅蓝色系&#xff0c;赋予人像自拍独特的清新、文艺风格&…

isp流程介绍(yuv格式阶段)

一、前言介绍 前面两章里面&#xff0c;已经分别讲解了在Raw和Rgb域里面&#xff0c;ISP的相关算法流程&#xff0c;从前面文章里面可以看到&#xff0c;在Raw和Rgb域里面&#xff0c;很多ISP算法操作&#xff0c;更像是属于sensor矫正或者说sensor标定操作。本质上来说&#x…

数巅智能携手北京昇腾创新中心深耕行业大模型应用

当前&#xff0c;AI技术正在加速向各行业深度渗透,成为驱动产业转型和社会经济发展的重要引擎。构建开放协作的AI应用生态体系、推动技术和应用深度融合&#xff0c;已成为行业发展的重要趋势。 近日&#xff0c;数巅智能与北京昇腾人工智能计算中心&#xff08;北京昇腾创新中…

【LangChain高级系列】LangGraph第一课

前言 我们今天直接通过一个langgraph的基础案例&#xff0c;来深入探索langgraph的核心概念和工作原理。 基本认识 LangGraph是一个用于构建具有LLMs的有状态、多角色应用程序的库&#xff0c;用于创建代理和多代理工作流。与其他LLM框架相比&#xff0c;它提供了以下核心优…

常见降维算法分析

一、常见的降维算法 LDA线性判别PCA主成分分析t-sne降维 二、降维算法原理 2.1 LDA 线性判别 原理 &#xff1a;LDA&#xff08;Linear Discriminant Analysis&#xff09;线性判别分析是一种有监督的降维方法。它的目标是找到一个投影方向&#xff0c;使得不同类别的数据在…

计算机二级(C语言)已过

非线性结构&#xff1a;树、图 链表和队列的结构特性不一样&#xff0c;链表可以在任何位置插入、删除&#xff0c;而队列只能在队尾入队、队头出队 对长度为n的线性表排序、在最坏情况下时间复杂度&#xff0c;二分查找为O(log2n)&#xff0c;顺序查找为O(n)&#xff0c;哈希查…

2025年3月,​韩先超对国网宁夏进行Python线下培训

大家好&#xff0c;我是韩先超&#xff01;在2025年3月3号和4号&#xff0c;为 宁夏国网 的运维团队进行了一场两天的 Python培训 &#xff0c;培训目标不仅是让大家学会Python编程&#xff0c;更是希望大家能够通过这门技术解决实际工作中的问题&#xff0c;提升工作效率。 对…

[计算机网络]物理层

文章目录 物理层的概述与功能传输介质双绞线:分类:应用领域: 同轴电缆&#xff1a;分类: 光纤&#xff1a;分类: 无线传输介质&#xff1a;无线电波微波&#xff1a;红外线&#xff1a;激光&#xff1a; 物理层设备中继器(Repeater)&#xff1a;放大器&#xff1a;集线器(Hub)&…

幂等操作及处理措施

利用token模式去避免幂等操作 按以上图所示&#xff0c;除了token,应该也可以把传入的参数用MD5加密&#xff0c;当成key放入redis里面&#xff0c;业务执行完后再删除这个key.如还没有执行完&#xff0c;则请不要重复操作。纯属个人理解

Matlab 数控车床进给系统的建模与仿真

1、内容简介 Matlab217-数控车床进给系统的建模与仿真 可以交流、咨询、答疑 2、内容说明 略 摘 要:为提高数控车床的加工精度,对数控 车床进给系统中影响加工精度的主要因素进行了仿真分析研 动系统的数学模型,利用MATLAB软件中的动态仿真工具 究:依据机械动力学原理建立了…

低成本自动化改造的18个技术锚点深度解析

执行摘要 本文旨在深入剖析四项关键的低成本自动化技术&#xff0c;这些技术为工业转型提供了显著的运营和经济效益。文章将提供实用且深入的指导&#xff0c;涵盖老旧设备联网、AGV车队优化、空压机系统智能能耗管控以及此类项目投资回报率&#xff08;ROI&#xff09;的严谨…

我国脑机接口市场规模将破38亿元,医疗领域成关键突破口

当人类仅凭"意念"就能操控无人机编队飞行&#xff0c;当瘫痪患者通过"脑控"重新站立行走&#xff0c;这些曾只存在于科幻电影的场景&#xff0c;如今正通过脑机接口技术变为现实。作为"十四五"规划中重点发展的前沿科技&#xff0c;我国脑机接口…

Edu教育邮箱申请成功下号

这里是第2部分 如你所见&#xff0c;我根本就没有考虑流量的问题&#xff0c; 如果你有幸看到前面的内容&#xff0c;相信你能自己找到这个后续。

【Linux进程控制一】进程的终止和等待

【Linux进程控制一】进程的终止和等待 一、进程终止1.main函数的return2.strerror函数3.库函数exit4.系统调用_exit和库函数exit的区别5.异常信号6.变量errno 二、进程等待1.什么是进程等待&#xff1f;2.wait接口3.status4.waitpid接口 一、进程终止 1.main函数的return 写C…

今日行情明日机会——20250509

上证指数今天缩量&#xff0c;整体跌多涨少&#xff0c;走势处于日线短期的高位~ 深证指数今天缩量小级别震荡&#xff0c;大盘股表现更好~ 2025年5月9日涨停股主要行业方向分析 一、核心主线方向 服装家纺&#xff08;消费复苏出口链驱动&#xff09; • 涨停家数&#xf…