Qt QML:同步滚动多个列表视图

Qt QML:同步滚动多个列表视图,qt,listview,mouseevent,qml,Qt,Listview,Mouseevent,Qml,我想要一个带有(水平)ListView委托的单个(垂直)ListView 水平代理应同步滚动。为此,我将Flickable放在ListView的顶部,并将水平ListView的contentX绑定到Flickable的contentX(垂直ListView的contentX也是如此)(注意:同步ListView滚动描述了不同的方法,但这在移动设备上似乎有性能问题) 下面的代码可以正常工作,但仍然存在以下问题 我没有得到矩形中的onclick(我在移除顶部Flickable时得到它) 我想要水平

我想要一个带有(水平)ListView委托的单个(垂直)ListView

水平代理应同步滚动。为此,我将Flickable放在ListView的顶部,并将水平ListView的contentX绑定到Flickable的contentX(垂直ListView的contentX也是如此)(注意:同步ListView滚动描述了不同的方法,但这在移动设备上似乎有性能问题)

下面的代码可以正常工作,但仍然存在以下问题

  • 我没有得到矩形中的onclick(我在移除顶部Flickable时得到它)
  • 我想要水平轻弹或垂直轻弹,但不能同时使用两者。我可以通过设置
    flickableDirection:Flickable.horizontalfick
    来限制顶部Flickable的轻弹,但是我不能再垂直轻弹了(我希望Flickable可以将未使用的鼠标事件传递到垂直列表视图,但这似乎没有发生)
关于如何解决这些问题的建议

感谢您的帮助

import QtQuick 2.0

Item {
    id: main
    visible: true
    width: 600
    height: 600

    ListView {
        id: verticalList
        width: parent.width;
        height: parent.height;
        contentY : flickable.contentY
        anchors.fill: parent
        spacing: 10
        orientation: ListView.Vertical
        model: 100
        delegate:
            ListView {
                id: horizontalList
                width: parent.width;
                height: 100;
                contentX : flickable.contentX
                spacing: 10
                orientation: ListView.Horizontal
                model: 20
                property var verticalIndex : index
                delegate:
                    Rectangle
                    {
                        property var colors : ['red', 'green', 'blue']
                        property var widths : [100, 200, 300]
                        height: 100
                        width: widths[(verticalIndex + model.index) % widths.length]
                        color: colors[model.index % colors.length]

                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Rectangle.onClicked")
                            }

                        }
                    }

           }

    }

    //on top a Flickable
    Flickable {
       id: flickable
       height: parent.height
       width: parent.width
       contentHeight: 100*100 //nrOfRows * rowHeight
       contentWidth: 20*300 //nrOfEvent * max/averageEventWidth
     }


}

我不是给你一个完美的解决方案,但它是有效的。当您使用
列表视图顶部的
Flickable
时,您将无法与其交互。因此,我使用了
Flickable
ListView
下面,并将
Flickable
ListView
contentX
绑定,但这会导致循环,我得到以下输出,但我们得到了所需的行为

QML Binding: Binding loop detected for property "value" 
编辑

因此,我没有对垂直列表使用
ListView
,而是使用了
Repeater
Column
并使用了属性绑定。现在很好用

以下是更新版本

import QtQuick 2.0

Item {
    id: main
    visible: true
    width: 600
    height: 600
    property bool virticalFlick: false  //To get either vertical or horizontal flicking

    Flickable {
        anchors.fill: parent
        contentWidth: contentItem.childrenRect.width
        contentHeight: contentItem.childrenRect.height
        flickableDirection: Flickable.VerticalFlick
        interactive: (virticalFlick === true)?true:false
        Column {
            id: column
            spacing: 10
            Repeater {
                id: repeater
                model: 20
                ListView {
                    id: horizontalList
                    width: 600;
                    height: 100;
                    clip: true
                    interactive: (virticalFlick === true)?false:true
                    spacing: 10
                    orientation: ListView.Horizontal
                    model: 20
                    property var verticalIndex : index
                    onMovingChanged: {
                        if(moving == true) {
                            for(var i=0; i<repeater.count ; i++) {
                                /* If the property is later assigned a static value from a JavaScript statement,
                            this will remove the binding.
                            However if the intention is to create a new binding then the property
                            must be assigned a Qt.binding() value instead. This is done by passing a function to
                            Qt.binding() that returns the desired result */
                                if (i !== index)
                                    repeater.itemAt(i).contentX = Qt.binding(function() { return contentX });
                            }
                        }
                        else {
                            for(var i=0; i<repeater.count ; i++) {
                                if (i !== index)
                                    repeater.itemAt(i).contentX = contentX; // This will remove binding
                            }
                        }

                    }

                    delegate: Rectangle {
                        property var colors : ['red', 'green', 'blue']
                        property var widths : [100, 200, 300]
                        height: 100
                        width: widths[(ListView.view.verticalIndex + model.index) % widths.length]
                        color: colors[model.index % colors.length]

                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Rectangle.onClicked")
                            }

                        }
                    }
                }
            }
        }
    }
}
导入QtQuick 2.0
项目{
id:main
可见:正确
宽度:600
身高:600
属性bool virticalFlick:false//以获取垂直或水平的flicking
轻快的{
锚定。填充:父级
contentWidth:contentItem.childrenRect.width
contentHeight:contentItem.childrenRect.height
flickableDirection:Flickable.VerticalFlick
交互式:(virticalFlick==真)?真:假
纵队{
id:列
间距:10
中继器{
id:中继器
型号:20
列表视图{
id:horizontalList
宽度:600;
身高:100;
剪辑:对
交互式:(virticalFlick==真)?假:真
间距:10
方向:ListView.Horizontal
型号:20
属性变量verticalIndex:索引
onMovingChanged:{
如果(移动==真){

对于(var i=0;i而言,以下方法确实有效,但最初的尝试似乎更为优雅

我仍然需要比较轻弹时的性能(fps),特别是在移动设备上。我也收到“绑定循环”警告,但我认为它们是误报

import QtQuick 2.0

Item {
id: main
visible: true
width: 600
height: 600

ListView {
    id: verticalList
    width: parent.width;
    height: parent.height;
    anchors.fill: parent
    spacing: 10
    cacheBuffer: 500 // in pixels
    orientation: ListView.Vertical
    model: 100
    property var activeIndex : 0
    property var lastContentX : 0
    delegate:
        ListView {
            id: horizontalList
            width: parent.width;
            height: 100;
            spacing: 10
            cacheBuffer: 500 // in pixels
            orientation: ListView.Horizontal
            model: 20
            property var verticalIndex : index
            delegate:
                Rectangle
                {
                    property var colors : ['red', 'green', 'blue']
                    color: colors[model.index % colors.length]

                    height: 100
                    property var widths : [100, 200, 300]
                    width: widths[(verticalIndex + model.index ) % widths.length]

                    MouseArea {
                        z:10
                        anchors.fill: parent
                        onClicked: {
                            console.log("Rectangle.onClicked")
                        }
                        onPressed: {
                            console.log("Rectangle.onPressed")
                        }
                        onReleased: {
                            console.log("Rectangle.onReleased")
                        }

                    }
                }

        onContentXChanged: {
            if(model.index === verticalList.activeIndex)
            {
                verticalList.lastContentX = contentX
            }
        }
        onMovementStarted: {
            verticalList.activeIndex = model.index
            unbind();
        }
        onMovementEnded: {
            bind();
        }

        Component.onCompleted: {
            bind();
        }

        function bind()
        {
            contentX = Qt.binding(function() { return verticalList.lastContentX })
        }
        function unbind()
        {
            contentX = contentX ;
        }
       }
  }
}

我最初的尝试需要进行以下修改

  • Flickable
    限制为
    Flickable方向:Flickable.horizontalfick
    并删除
    verticalList上的
    contentY:Flickable.contentY

  • 这样,就不再有垂直滚动。可以通过在
    列表视图中移动
    Flickable
    来解决这一问题

  • 通过将以下
    MouseArea
    添加到
    Flickable

例如


感谢您的输入。水平翻转确实不平滑(立即停止),很可能是由于绑定循环。但我可能会在此版本的基础上进行更多的实验。再次感谢!翻转现在确实平滑。但是,我确实需要一个ListView iso a中继器(因为中继器在可见窗口外使用了更多的内存和油漆,这在设置QSG_VISUALIZE=overdraw时可以看到)。此外,我需要垂直和水平滚动(但没有我最初尝试的对角线滚动)。我的答案符合这些要求,但我仍然需要比较两个选项的wrt性能。其中有许多绑定循环。我认为这将导致一些主要的性能问题。
MouseArea {
   anchors.fill: parent
   //see http://stackoverflow.com/questions/29236762/mousearea-inside-flickable-is-preventing-it-from-flicking
   onReleased: {
      if (!propagateComposedEvents) {
         propagateComposedEvents = true
      }
   }
}