连接自定义滚动条和 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的主要内容,如果未能解决你的问题,请参考以下文章