【问题标题】:Connect custom Scrollbar and Flickable连接自定义滚动条和 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
                    }
                }
            }
        }
    }
}

尝试拖动画布时出错

【问题讨论】:

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

标签: qt binding qml qt5


【解决方案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{}
    }
}

【讨论】:

  • 我需要显示内容的某一部分,具体取决于滚动条的位置。滚动条的滚动距离远大于内容的实际大小。
猜你喜欢
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多