Connect custom Scrollbar and Flickable
Unsolved
QML and Qt Quick
-
I have a virtual large table, and an area that is real drawn. Depending on the position of the content, a certain part of the virtual table is displayed.
And now I'm trying in different ways to synchronize the content and the scrollbar.
In this case, the scrollbar jumps with the content.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 } } } } } }