连接自定义滚动条和 Flickable

Posted

技术标签:

【中文标题】连接自定义滚动条和 Flickable【英文标题】:Connect custom Scrollbar and Flickable 【发布时间】:2021-07-21 11:55:26 【问题描述】:

我有一个虚拟的大桌子和一个真实绘制的区域。根据内容的位置,显示虚拟表的某个部分。 现在我正在尝试以不同的方式来同步内容和滚动条。 在这种情况下,滚动条会随内容一起跳动。

AreaScrollBar.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

ScrollBar 
    id: root
    /// Virtual content size
    /// 50000
    property real virtualContentSize: 0

    /// Real content size
    /// 2000
    property real contentSize: 0

    /// Visible content size
    /// 500
    property real visibleSize: orientation === Qt.Horizontal ? width : height

    /// Position offset step.
    /// 100
    property real stepAreaPosition: 1

    /// The position of the component area [0 .. virtualContentSize - contentSize]
    property real areaPosition: 0

    /// [0 .. contentSize - visibleSize]
    property real positionInArea: 0

    property QtObject priv: QtObject 
        /// В запасе после перестроения
        readonly property real buffer: 0.2 * contentSize - (0.2 * contentSize) % stepAreaPosition
    

    size: (orientation === Qt.Horizontal ? width : height) / virtualContentSize
    policy: ScrollBar.AlwaysOn
    onPositionChanged: 
        console.log('onPosChanged', position)
        let arP = -1
        let pia = -1
        if (position < 0) 
            position = 0
         else if (position + size > 1) 
            position = 1 - size
        

        if (position * virtualContentSize + visibleSize
                > areaPosition + 0.9 * contentSize) 
            pia = priv.buffer
         else if (position * virtualContentSize - areaPosition < 0.1 * contentSize) 
            pia = contentSize - (priv.buffer + visibleSize)
         else 
            positionInArea = position * virtualContentSize - areaPosition
            return
        

        arP = position * virtualContentSize - pia
        let arp2 = 0
        if (arP < 0) 
            arp2 = 0
         else if (arP > virtualContentSize - contentSize) 
            arp2 = virtualContentSize - contentSize
         else 
            arp2 = arP - (arP % stepAreaPosition)
        

        positionInArea = position * virtualContentSize - arp2
        areaPosition = arp2
    

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Window 
    width: 600
    height: 600
    visible: true
    title: qsTr("Hello World")

    Column 
        focus: true
        Keys.onDownPressed:  vSb.position += 10 / vSb.virtualContentSize
        Keys.onUpPressed:    vSb.position -= 10 / vSb.virtualContentSize
        Keys.onLeftPressed:  hSb.position -= 10 / hSb.virtualContentSize
        Keys.onRightPressed: hSb.position += 10 / hSb.virtualContentSize
        Row 
            Column 
                Text  text: qsTr("vSb.position %1").arg(vSb.position) 
                Text  text: qsTr("vSb.areaPosition %1").arg(vSb.areaPosition) 
                Text  text: qsTr("vSb.positionInArea %1").arg(vSb.positionInArea) 
            
            Item 
                width: 100
                height: 1
            

            Column 
                Text  text: qsTr("hSb.position %1").arg(hSb.position) 
                Text  text: qsTr("hSb.areaPosition %1").arg(hSb.areaPosition) 
                Text  text: qsTr("hSb.positionInArea %1").arg(hSb.positionInArea) 
            
        


        Rectangle 
            id: mainArea
            width: 500
            height: 500
            clip: true
            color: "gray"
            border.color: "darkgray"
            border.width: 3
            property int _rows: 50
            property int _columns: 10
            property int _virtualRows: 500
            property int _virtualColumns: 50
            property int _rectWidth: 90
            property int _rectHeight: 90
            property int _spacing: 10
            property int _virtualContentWidth: _virtualColumns * (_rectWidth + _spacing)
            property int _virtualContentHeight: _virtualRows * (_rectHeight + _spacing)

            Flickable 
                id: _flick
                anchors.fill: parent
                contentWidth: mainArea._columns * (mainArea._rectWidth + mainArea._spacing)
                contentHeight: mainArea._rows * (mainArea._rectHeight + mainArea._spacing)
                Column 
                    spacing: mainArea._spacing
                    Repeater 
                        model: mainArea._rows
                        Row 
                            property int rowInd: index
                            spacing: mainArea._spacing
                            Repeater 
                                model: mainArea._columns
                                Rectangle 
                                    id: rect
                                    property int columnInd: index
                                    width: mainArea._rectWidth
                                    height: mainArea._rectHeight
                                    color: "#3c324a"
                                    Column 
                                        Repeater 
                                            model: rect.height / 10
                                            Rectangle 
                                                width: rect.width
                                                height: 10
                                                color: Qt.lighter(rect.color, 1 + index * 0.1)
                                            
                                        
                                    
                                    Text 
                                        anchors.fill: parent
                                        horizontalAlignment: Text.AlignLeft
                                        verticalAlignment: Text.AlignTop
                                        text: '[%2, %3]'.arg(rowInd).arg(columnInd)
                                        font.pointSize: 7
                                    
                                    Text 
                                        anchors.fill: parent
                                        horizontalAlignment: Text.AlignHCenter
                                        verticalAlignment: Text.AlignVCenter
                                        text: ('content\n[%1, %2]'
                                               .arg(vSb.areaPosition / vSb.stepAreaPosition + rowInd)
                                               .arg(hSb.areaPosition / hSb.stepAreaPosition + columnInd))
                                        font.pixelSize: 15
                                    
                                
                            
                        
                    
                
                interactive: true

                Binding on contentX 
                    value: 
                        console.log('_flick.contentX', _flick.contentX, hSb.positionInArea)
                        return hSb.positionInArea
                    
                

                Binding on contentY 
                    value: 
                        console.log('_flick.contentY', _flick.contentY, vSb.positionInArea)
                        return vSb.positionInArea
                    
                
            
            AreaScrollBar 
                id: vSb
                orientation: Qt.Vertical
                stepAreaPosition: mainArea._rectHeight + mainArea._spacing
                virtualContentSize: mainArea._virtualRows * stepAreaPosition
                contentSize: mainArea._rows * stepAreaPosition
                anchors.top: parent.top
                anchors.right: parent.right
                anchors.bottom: hSb.top

                Binding on position 
                    value: 
                        console.log('vSb.position', _flick.contentY,
                                    vSb.areaPosition, vSb.virtualContentSize)
                        return (_flick.contentY + vSb.areaPosition) / vSb.virtualContentSize
                    
                
            

            AreaScrollBar 
                id: hSb
                orientation: Qt.Horizontal
                stepAreaPosition: mainArea._rectWidth + mainArea._spacing
                virtualContentSize: mainArea._virtualColumns * stepAreaPosition
                visibleSize: mainArea.width
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                anchors.right: vSb.left
                Binding on position 
                    value: 
                        console.log('hSb.position', _flick.contentX,
                                    hSb.areaPosition, hSb.virtualContentSize)
                        return (_flick.contentX + hSb.areaPosition) / hSb.virtualContentSize
                    
                
            
        
    

尝试拖动画布时出错

【问题讨论】:

抱歉,我不明白,您希望这段代码以其他方式工作吗? 现在滚动条跳跃 哦,是的。现在我明白了。 【参考方案1】:

这一直是 Qt 项目添加 QML 时的问题。人们试图跳过学习 C++ 并用 javascript 做所有事情。

您需要阅读TableView 文档。一个 TableView 已经是 Flickable 并且为 TableModel 提供了一个矩形视图。无需尝试重​​新发明***。

然后look at this 为 TableView 添加滚动条。

正确的解决方案始终是在 C++ 中创建所有数据,仅使用 QML 进行显示

一旦人们开始尝试在 QML/JavaScript 中实现逻辑,***就会从购物车中脱落。

【讨论】:

这只是一个例子。我需要展示数百万行的模型。 QML 无法在如此大的表上正常工作。这就是我制作自定义滚动条的原因。中继器只是一个例子 再一次,你没有阅读。数据以 C++ 模型存储。 TableView 是模型上方的一个窗口,滚动条可以正常工作。它旨在“查看”具有数百万行和数百列的 SQL 游标。 实际上,我看到代表开始移动数百万行。 ListView model: 10000000; delegate: Text text: index; - 走到表尾【参考方案2】:

请测试这段代码,我使用了你的部分代码,但我并没有将它与我只使用 Flickable 和 Scrollbar 的位置以及用于创建矩阵的中继器复杂化。 我测试了一下,这样滚动条没有跳动。

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5

Window 
    id:mainArea
    visible: true
    width: 640
    height: 480
    title: qsTr("Flickable and Scrollbar ")

    property int _rows: 50
    property int _columns: 10
    property int _virtualRows: 500
    property int _virtualColumns: 50
    property int _rectWidth: 90
    property int _rectHeight: 90
    property int _spacing: 10
    property int _virtualContentWidth: _virtualColumns * (_rectWidth + _spacing)
    property int _virtualContentHeight: _virtualRows * (_rectHeight + _spacing)


    Flickable

        width: parent.width
        height: parent.height
        contentHeight: mColumnId.implicitHeight
        contentWidth:  mColumnId.implicitWidth



        Column
            id : mColumnId
            anchors.fill: parent

            spacing: mainArea._spacing
            Repeater 
                model: mainArea._rows
                Row 
                    property int rowInd: index
                    spacing: mainArea._spacing
                    Repeater 
                        model: mainArea._columns
                        Rectangle 
                            id: rect
                            property int columnInd: index
                            width: mainArea._rectWidth
                            height: mainArea._rectHeight
                            color: "#3c324a"
                            Column 
                                Repeater 
                                    model: rect.height / 10
                                    Rectangle 
                                        width: rect.width
                                        height: 10
                                        color: Qt.lighter(rect.color, 1 + index * 0.1)
                                    
                                
                            
                            Text 
                                anchors.fill: parent
                                horizontalAlignment: Text.AlignLeft
                                verticalAlignment: Text.AlignTop
                                text: '[%2, %3]'.arg(rowInd).arg(columnInd)
                                font.pointSize: 7
                            
                            Text 
                                anchors.fill: parent
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                                text: "Parisa"
                                font.pixelSize: 15
                            
                        
                    
                
            



        

        ScrollBar.vertical: ScrollBar
        ScrollBar.horizontal: ScrollBar
    

【讨论】:

我需要显示内容的某一部分,具体取决于滚动条的位置。滚动条的滚动距离远大于内容的实际大小。

以上是关于连接自定义滚动条和 Flickable的主要内容,如果未能解决你的问题,请参考以下文章

JComboBox自定义滚动条和去掉默认背景

QML 中的 Flickable / ScrollView 带有始终可见的滚动条,在右下角不重叠

如何用 CSS 改变滚动条的位置?

CSS滚动条

滚动条和滚动事件

隐藏列表框滚动条和同步滚动