QML 中具有嵌套滚动区域的二维 table
Two-dimensional table with nested scrolling areas in QML
我想在 QML 中创建一个电视节目表,其中纵轴是频道列表,横轴是基于时间的。例如像
(来源:zappware.com)
最初,我创建了
- 一个垂直的ListView
- model = 频道列表
- delegate = 水平 ListView
- 每个水平的ListView都有
- model = 事件列表
- 委托 = 宽度与事件持续时间成正比的项目
到目前为止一切顺利。唯一的缺点是水平 ListView 一个一个滚动,而它们应该一起滚动。
所以不知何故,每个水平 ListView 的 contentX 属性 应该绑定到 moving/flicking 水平 ListView 的 contentX 属性。请注意,此绑定是动态的:在第一行中滑动时,所有其他行都应绑定到第一行的 contentX。但是在第二行滑动时应该改变这个。
关于如何做到这一点有什么建议吗?
我尝试了一种不同的方法
- 在垂直 ListView 的顶部创建一个 Flickable Item(contentWidth 为完整时间 -window)。
- 将每个水平 ListView 绑定到此 Flickable 的 contentX(这是静态绑定)
这导致了很好的同步滚动,但我仍然有一些问题
- 我不得不采取一些技巧来确保轻弹只是水平或垂直而不是两者
- 我无法再点击个别活动;我猜事件被 Flickable
拦截了
- 我也不确定这种具有巨大 contentWidth 的 Flickable 对内存的影响?
感谢反馈!
我想说频道只有一个垂直列表视图。但只是频道名称,而不是实际的节目。除了程序的水平视图,您可以将它们全部塞进一个 flickable 中,使用开始时间和持续时间通过将它们的 x 和 width 属性绑定到前者来在 flickable 中布局程序。
然后您可以将频道列表视图与节目项的垂直滚动绑定在一起,这样您就可以将节目与相应的频道相对应。这样您就可以从两者垂直滚动,而只水平滚动程序。
这是一个简单的例子:
ApplicationWindow {
id: main
width: 500
height: 100
visible: true
color: "white"
ListModel {
id: modC
ListElement { name: "Ch1" }
ListElement { name: "Ch2" }
ListElement { name: "Ch3" }
}
ListModel {
id: modP1
ListElement { name: "p1"; start: 0; duration: 6 }
ListElement { name: "p2"; start: 6; duration: 6 }
ListElement { name: "p3"; start: 12; duration: 6 }
ListElement { name: "p4"; start: 18; duration: 6 }
}
ListModel {
id: modP2
ListElement { name: "p1"; start: 0; duration: 12 }
ListElement { name: "p2"; start: 12; duration: 12 }
}
ListModel {
id: modP3
ListElement { name: "p1"; start: 0; duration: 8 }
ListElement { name: "p2"; start: 8; duration: 8 }
ListElement { name: "p3"; start: 16; duration: 8 }
}
property var subMod : [ modP1, modP2, modP3 ]
Component {
id: progDelegate
Rectangle {
property var source
x: source.start * 50
width: source.duration * 50
height: 50
color: "lightblue"
border.color: "black"
Text {
text: source.name
}
}
}
Row {
anchors.fill: parent
ListView {
id: list
height: parent.height
width: 100
model: modC
delegate: Item {
width: 100
height: 50
Rectangle {
anchors.fill: parent
color: "red"
border.color: "black"
Text {
anchors.centerIn: parent
text: name
}
}
Component.onCompleted: {
var mod = subMod[index]
for (var i = 0; i < mod.count; ++i) progDelegate.createObject(flick.contentItem, {"source": mod.get(i), "y": index * 50})
}
}
}
Flickable {
id: flick
height: parent.height
width: parent.width - list.width
contentWidth: 1200
contentHeight: contentItem.childrenRect.height
clip: true
flickableDirection: Flickable.HorizontalFlick
contentY: list.contentY
}
}
}
我想在 QML 中创建一个电视节目表,其中纵轴是频道列表,横轴是基于时间的。例如像
(来源:zappware.com)
最初,我创建了
- 一个垂直的ListView
- model = 频道列表
- delegate = 水平 ListView
- 每个水平的ListView都有
- model = 事件列表
- 委托 = 宽度与事件持续时间成正比的项目
到目前为止一切顺利。唯一的缺点是水平 ListView 一个一个滚动,而它们应该一起滚动。
所以不知何故,每个水平 ListView 的 contentX 属性 应该绑定到 moving/flicking 水平 ListView 的 contentX 属性。请注意,此绑定是动态的:在第一行中滑动时,所有其他行都应绑定到第一行的 contentX。但是在第二行滑动时应该改变这个。
关于如何做到这一点有什么建议吗?
我尝试了一种不同的方法
- 在垂直 ListView 的顶部创建一个 Flickable Item(contentWidth 为完整时间 -window)。
- 将每个水平 ListView 绑定到此 Flickable 的 contentX(这是静态绑定)
这导致了很好的同步滚动,但我仍然有一些问题
- 我不得不采取一些技巧来确保轻弹只是水平或垂直而不是两者
- 我无法再点击个别活动;我猜事件被 Flickable 拦截了
- 我也不确定这种具有巨大 contentWidth 的 Flickable 对内存的影响?
感谢反馈!
我想说频道只有一个垂直列表视图。但只是频道名称,而不是实际的节目。除了程序的水平视图,您可以将它们全部塞进一个 flickable 中,使用开始时间和持续时间通过将它们的 x 和 width 属性绑定到前者来在 flickable 中布局程序。
然后您可以将频道列表视图与节目项的垂直滚动绑定在一起,这样您就可以将节目与相应的频道相对应。这样您就可以从两者垂直滚动,而只水平滚动程序。
这是一个简单的例子:
ApplicationWindow {
id: main
width: 500
height: 100
visible: true
color: "white"
ListModel {
id: modC
ListElement { name: "Ch1" }
ListElement { name: "Ch2" }
ListElement { name: "Ch3" }
}
ListModel {
id: modP1
ListElement { name: "p1"; start: 0; duration: 6 }
ListElement { name: "p2"; start: 6; duration: 6 }
ListElement { name: "p3"; start: 12; duration: 6 }
ListElement { name: "p4"; start: 18; duration: 6 }
}
ListModel {
id: modP2
ListElement { name: "p1"; start: 0; duration: 12 }
ListElement { name: "p2"; start: 12; duration: 12 }
}
ListModel {
id: modP3
ListElement { name: "p1"; start: 0; duration: 8 }
ListElement { name: "p2"; start: 8; duration: 8 }
ListElement { name: "p3"; start: 16; duration: 8 }
}
property var subMod : [ modP1, modP2, modP3 ]
Component {
id: progDelegate
Rectangle {
property var source
x: source.start * 50
width: source.duration * 50
height: 50
color: "lightblue"
border.color: "black"
Text {
text: source.name
}
}
}
Row {
anchors.fill: parent
ListView {
id: list
height: parent.height
width: 100
model: modC
delegate: Item {
width: 100
height: 50
Rectangle {
anchors.fill: parent
color: "red"
border.color: "black"
Text {
anchors.centerIn: parent
text: name
}
}
Component.onCompleted: {
var mod = subMod[index]
for (var i = 0; i < mod.count; ++i) progDelegate.createObject(flick.contentItem, {"source": mod.get(i), "y": index * 50})
}
}
}
Flickable {
id: flick
height: parent.height
width: parent.width - list.width
contentWidth: 1200
contentHeight: contentItem.childrenRect.height
clip: true
flickableDirection: Flickable.HorizontalFlick
contentY: list.contentY
}
}
}