In the below sample code, I set z property for the highlight item and depending on the value, it shows up to the user. The z property can also be configured with real value.
It means z value can have fractional values such as 0.1 or 1.2, like that.
Can anyone explain the purpose of z value should be fractional or real value in QML ListView?
import QtQuick 2.8
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Sample List View")
property var delHeight: 50
ListView {
id: listView
anchors.fill: parent
cacheBuffer: 100
footer: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightyellow"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Footer"
}
}
header: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightblue"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Header"
}
z: 2
}
headerPositioning: ListView.OverlayHeader
highlight: Rectangle {
color: "white"
opacity: 0.5
border.color: "blue"
border.width: 5
z: 1.2
Component.onCompleted: {
console.log ("Created hightlight component with z factor: " + z)
}
}
// highlightMoveDuration: 10000
// highlightRangeMode: ListView.ApplyRange
keyNavigationEnabled: true
model: 20
delegate: componentId
layoutDirection: Qt.RightToLeft
orientation: ListView.Vertical
snapMode: ListView.SnapOneItem
Component.onCompleted: {
currentIndex = 5
}
focus: true
onFocusChanged: {
console.log ("Focus: " + focus)
}
}
Component {
id: componentId
Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightgreen"
border.color: "black"
border.width: (listView.currentIndex === index) ? 5 : 1
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Element: " + index
}
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
Component.onCompleted: {
console.log ("Created component: " + index)
}
Component.onDestruction: {
console.log ("Destroyed component: " + index)
}
}
}
}
The z property of an item gives the stacking order to that item.
Meaning, if you are constructing two Rectangles one after the other than recently constructed rectangle will be stacked on top the previously constructed one.
Ex code:
Item {
Rectangle {
color: "red"
width: 100; height: 100
}
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
}
}
Here red rectangle stacked below blue rectangle.
Now QML gives you chance to change the stacking order through z property of the item.
in the above example if I assign z property of the red rectangle to have a value of anything above 0, I would see it on top of blue rectangle. So z property has changed the stacking order for the sibling item.
The purpose of the z property stays the same in case of ListView highlight. When you want to see the highlight item then you have to give it a value which is greater than the items which will be constructed. You can check this by just setting z property for the componentIds rectangle to some higher value than highlights z value.
NOTE: it only works for sibling items.
More explanation can be found here
Read about the real type here
Related
I have an issue with setting coordinates inside Repeater:
import QtQuick
Window {
id: mainWindow
property int wi: 640
property int he: 500
width: wi
height: he
visible: true
title: qsTr("Game")
Rectangle {
id: gameWindow
width: wi/1.6
height: he
anchors.right: parent.right
visible: true
color: "black"
clip: true
Grid {
id: gameGrid
columns: 25
spacing: 0
rows: 32
anchors.fill: parent
Repeater {
model: 600
Rectangle {
width: wi/40
height: 20
border.width: 2
color: "grey"
}
}
}
Grid {
id: sGrid
columns: gameGrid.columns
spacing: gameGrid.spacing
rows: gameGrid.rows
anchors.fill: gameGrid
Repeater {
model: 5
Rectangle {
// anchors.horizontalCenter: sGrid.horizontalCenter
// anchors.verticalCenter: sGrid.verticalCenter
// x: (wi/2) + (index * (wi/40) )
// y: he/2
width: wi/40
height: 20
border.width: 1
color: "red"
}
}
}
}
}
Whole code above, but my question is about the second Repeater with 5 Rectangles.
I have tried to solve that with many ways. Most obvious seemed to me placing coordinates inside Repeater, but now I know it does not work like this - I have to place coordinates somehow inside Rectangle. I have commented code, where are the ways I have tried to solve this.
Anchors work very well - it places the first element exactly where I am expecting.
Problem appears with the next elements. They are placing inside the same element of Grid. I do not understand why the coordinates does not working. Documentation shows I could use "index", don't know, maybe the point is that's "read only" property? I have tried to set Rectangle with prefix "delegate:" with the same result as well.
In your question, you mention you have Grid + Repeater + Rectangle. I am not sure what you want to achieve, but, it feels like you may have better luck by going GridView + Rectangle because GridView supports a model.
Since you want coordinate control of your Rectangles, it is possible to do this alone with Repeater + Rectangle. No need for Grid since the Grid will impact the coordinate system of your Rectangle.
Below illustrates how you can use a simple ListModel to control the placement of your Rectangles:
import QtQuick
import QtQuick.Controls
Page {
Repeater {
model: ListModel {
ListElement { p:100; q:100; w:50; h:50; c:"red"; o:0 }
ListElement { p:200; q:100; w:50; h:50; c:"green"; o:15 }
ListElement { p:300; q:200; w:50; h:50; c:"blue"; o:30 }
ListElement { p:300; q:300; w:50; h:50; c:"orange"; o:45 }
ListElement { p:200; q:400; w:50; h:50; c:"purple"; o:60 }
}
delegate: Rectangle {
x: p
y: q
width: w
height: h
color: c
rotation: o
}
}
}
You can Try it Online!
[EDIT]
With the following, it shows how you could use index in 10 delegates to place your rectangles using a formula:
import QtQuick
import QtQuick.Controls
Page {
Repeater {
model: 10
delegate: Rectangle {
x: 100 + (index % 4) * 100
y: 100 + Math.floor(index / 4) * 100
width: 50
height: 50
color: ["green","red","orange","blue","purple"][index%5]
rotation: index * 10
Text {
anchors.centerIn: parent
text: index
color: "white"
}
}
}
}
You can Try it Online!
This code does produce checkboxes in a tableview but when I click on the checkbox it becomes big. I want it to remain of a constant size.
Please guide.
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
Rectangle
{
id: rightside
anchors.fill: parent
height: parent.height
width: 1500
TableView
{
anchors.fill: parent
TableViewColumn
{
role: "selectall"
title: "Select All"
width: 100
delegate: CheckBox
{
anchors.fill: parent
checked: false
}
}
TableViewColumn {
role: "size"
title: "Size"
width: 100
}
TableViewColumn
{
role: "last_updated"
title: "Last Updated"
width: 100
delegate: Component
{
Rectangle
{
height: 100
width: 120
id: head
RowLayout
{
height: parent.height
width: parent.width
Rectangle
{
height: 20
width: 20
color: "red"
border.color: "black"
radius: 100
MouseArea
{
anchors.fill: parent
onClicked: parent.color = "grey"
}
}
}
}
}
}
model: ListModel
{
id: mymodel
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
}
}
There are lots of way to solve your problem. But first, let's do proper distinction between Qt Qtuick Controls versions. To do it, use this import statement:
import QtQuick.Controls 1.4 as QC1
And respectively use all components that requires QC1, e.g.: QC1.TableView, QC1.TableViewColumn.
In your example you are getting overlapping of components. To avoid it in terms of QC1 you can define a higher row delegate for your TableView. But this discards the default style. Simple example of its usage with style goes here:
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base
return styleData.selected ? myPalette.highlight : baseColor
}
}
As result you'll get this:
Another option in terms of QC2 is to redefine indicator style of CheckBox. Below you'll find an example that could possibly fit your app, based on Customizing CheckBox documentation; so your CheckBox delegate will look like this:
delegate: CheckBox {
id: control
anchors.fill: parent
checked: false
indicator: Rectangle {
id: outer
readonly property int size: 18
implicitWidth: size
implicitHeight: size
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 4
border.color: control.down ? "orangered" : "orange"
Rectangle {
id: inner
anchors.centerIn: parent
width: outer.size/2
height: width
radius: 3
color: control.down ? "orangered" : "orange"
visible: control.checked
}
}
}
As result you'll get this:
I was working with a GridView in QML. When I click on an element, I want to following highlight to happen:
However, my problem is that I want the blue color to appear below the delegate (not in the white area but still visible on the transparent side part) while the checkmark appears above (so it is visible). I have tried playing around with the z values so that the lowest z should be the blue rectangle, the middle should be the white rectangle part of the delegate, and the highest should be the check mark but i can't seem to make it work. Either the highlight or the delegate has to be on top. Does anyone know any way I can fix this so that it works correctly?
Code for highlight:
highlight:
Rectangle {
z:5
color: "steelblue"; radius: 5; opacity: 0.5
Image{
z:8
id: checkMark
visible: found;
x: parent.width-8-width
y: 8
width: 40;
height: 40;
source: "file:///Users/arjun/Documents/CompetitiveBall/images/checkMark.png"
}
}
Code for delegate:
Component {
id: contactsDelegate
Rectangle{
width: grid.cellWidth
height: grid.cellHeight
color: "transparent"
Rectangle {
z:7
width: grid.cellWidth-20
height: grid.cellHeight-20
id: wrapper
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
border.width: 3
border.color: "black"
radius: 5;
Image{
id: mImage
x:parent.x
width: 65
height:65;
source: picSource
}
Text{
width: grid.cellWidth-15
y: mImage.y+mImage.height+4
anchors.horizontalCenter: parent.horizontalCenter
id: nameText
text: name
font.family: "Palatino Linotype"
font.bold: (grid.isCurrentItem===true)?"true":"false"
horizontalAlignment: Text.AlignHCenter
color:"#050027"
}
MouseArea{
anchors.fill: parent
onClicked:{
console.log("Clicked on :" + name)
//what happens when u click
grid.currentIndex=index;
}
}
}
}
}
Since you want part of the highlight to be underneath the delegate and part of it to be on top, you need to break it up into different pieces. I tested the code below with Qt 5.15.0. I made the normal highlight object draw underneath the delegate. Then I added another Rectangle that follows the highlight that draws on top of the delegate.
GridView
{
id: lv
anchors.fill: parent
anchors.margins: 50
cellWidth: 50
cellHeight: 50
model: 30
// By default, highlight draws behind delegates
// (You can specify a positive z-value to make it draw on top)
highlight: Item
{
Rectangle
{
anchors.centerIn: parent
width: 50
height: 50
color: "green"
}
}
delegate: Rectangle
{
width: 30
height: 30
color: "red"
MouseArea
{
anchors.fill: parent
onClicked: lv.currentIndex = index;
}
}
// This will draw on top of the delegates
// (You can change that by specifying a negative z-value.)
Rectangle
{
id: checkbox
x: lv.highlightItem.x - lv.contentX
y: lv.highlightItem.y - lv.contentY
width: 10
height: 10
color: "blue"
}
}
I'm struggling with an issue and I can't find a solution.
I am developing an embedded device (a graphic interface for an oven) with Qt.
I have the main page where I have a SwipeView with a grid inside to show n-tiles.
The tile is defined in another object.qml that I call in the main page and on each tile I have an image with 3 dots and when you click on it, a popup comes out that lets you edit the tile.
The problem is showing this popup because when I click on the three-dot-image the popup object shows underneath the tile and I can't seem to solve this problem.
I tried changing the z property but it doesn't work.
Anyway, I'm gonna attach some code and two images of the interface.
Thank you
MyPgRecipeGrid.qml this is my main page
import QtQuick 2.6
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
SwipeView {
id: view
property int numProgrammi : myVar.progCategoryRecipeGrid.count
currentIndex: 0
width:parent.width
height: parent.height*0.75
anchors.top: searchRect.bottom; anchors.topMargin: parent.height*0.025
Repeater {
id: gridRepeat
property int numgrid: ((Math.floor(view.numProgrammi/12)) + (((view.numProgrammi%12)==0) ? 0 : 1))
model: numgrid
delegate: Rectangle {
color: "transparent"
GridView {
id:grid
width: parent.width*0.95; height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
clip: false
property int numPage: index
cellWidth: 190; cellHeight: 180
interactive: false
model: 12 //Draws 12 tiles
delegate: Rectangle {
width: grid.cellWidth; height: grid.cellHeight
color: "transparent"
TileCategoryRecipeGrid {
property int indicelista: ((grid.numPage * 12)+index < myVar.progCategoryRecipeGrid.count) ? ((grid.numPage * 12 )+index) : 0
visible: ((grid.numPage*12)+index) < view.numProgrammi ? true : false
nomeTypCat: qsTr(myVar.progCategoryRecipeGrid.get(indexlist).nameCategory)
urlimageTypCat: myVar.progCategoryRecipeGrid.get(indexlist).urlCategoryImage
emptyTypCat: myVar.progCategoryRecipeGrid.get(indexlist).emptyCategory
userTypCat: myVar.progCategoryRecipeGrid.get(indexlist).userCategory
}
}
}
}
}
}
TileCategoryRecipeGrid.qml this is where I build the tile
import QtQuick 2.6
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
//Tile
Button{
id: tileCategoryRecipeGrid
width: 180; height: 172
property string myFont: myVar.medium
property string myFont2: myVar.fontTile
background: Rectangle {
anchors.fill: parent;
color: "transparent"; radius: 2
opacity: parent.down ? 0.80 : 1
clip: true
Image {
anchors.fill: parent
anchors.horizontalCenter: parent.horizontalCenter;
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenterOffset: -10
source: image
}
}
}
Button{
id: btnPoints
width: 35; height: 35
anchors.right: parent.right; anchors.rightMargin: 3
anchors.top: parent.top; anchors.topMargin: 3
background: Rectangle {
id: threePoints
anchors.fill: parent;
color: "transparent";
opacity: parent.down ? 0.25 : 1
Image {
anchors.fill: parent
source: contextMenu.visible ? "qrc:/QmlContents/IMG/close_btn.png" : "qrc:/QmlContents/IMG/threepoints.png"
}
}
onClicked: {
contextMenu.visible == false ? contextMenu.visible = true : contextMenu.visible = false
indexLocationPopup = index
}
}
Text {
id: showCookingTime
anchors.left: parent.left; anchors.leftMargin: 42
anchors.top: parent.top; anchors.topMargin: 3
text: qsTr("00:20"); color: clrPaletta.white
font.family: myFont; font.pixelSize: 20
}
contentItem: Rectangle{
anchors.fill: parent; opacity: parent.down ? 0.80 : 1
color: "transparent"
Text{
color: clrPaletta.white; opacity: 0.50
text: qsTr("cooking type")
font.family: myFont ; font.pixelSize: 17
anchors.left: parent.left ; anchors.leftMargin: parent.width*0.05
anchors.bottom: parent.bottom; anchors.bottomMargin: parent.height*0.10
}
//Popup edit tile
ContextMenuEditTile {
id: contextMenu
visible: false
x: {
switch(indexLocationPopup) {
case 0: dp(parent.width*0.60); break
case 1: -dp(parent.width-parent.width*0.70); break
case 2: -dp(parent.width-parent.width*0.70); break
case 3: dp(parent.width*0.60); break
case 4: -dp(parent.width-parent.width*0.70); break
case 5: -dp(parent.width-parent.width*0.70); break
case 6: dp(parent.width*0.60); break
case 7: -dp(parent.width-parent.width*0.70); break
case 8: -dp(parent.width-parent.width*0.70); break
case 9: dp(parent.width*0.60); break
case 10: -dp(parent.width-parent.width*0.70); break
case 11: -dp(parent.width-parent.width*0.70); break
}
}
y: {
switch(indexLocationPopup) {
case 0: dp(parent.height-parent.height*0.75); break
case 1: dp(parent.height-parent.height*0.75); break
case 2: dp(parent.height-parent.height*0.75); break
case 3: dp(parent.height-parent.height*0.75); break
case 4: dp(parent.height-parent.height*0.75); break
case 5: dp(parent.height-parent.height*0.75); break
case 6: dp(parent.height-parent.height*0.75); break
case 7: dp(parent.height-parent.height*0.75); break
case 8: dp(parent.height-parent.height*0.75); break
case 9: -dp(parent.height+parent.height*0.30); break
case 10: -dp(parent.height+parent.height*0.30); break
case 11: -dp(parent.height+parent.height*0.30); break
}
}
z: ((indexLocationPopup >= 0) && (indexLocationPopup <= 11)) ? 99 : 0
}
}
}
ContextMenuEditTile.qml and this is my popup
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
Rectangle {
id:contextMenu
width: 245; height: 265
visible: false
radius: 2;
color: clrPaletta.tileMenuclr1
ListView {
id:listView
anchors.fill: parent; clip: true;
boundsBehavior: Flickable.StopAtBounds
model: ListModel{
id: model
ListElement{ name:qsTr("Accessories"); urlImage: "qrc:/QmlContents/IMG/accessories.png" }
ListElement{ name:qsTr("Copy"); urlImage: "qrc:/QmlContents/IMG/copy.png" }
ListElement{ name:qsTr("Rename"); urlImage: "qrc:/QmlContents/IMG/rename_folder.png" }
ListElement{ name:qsTr("Modify"); urlImage: "qrc:/QmlContents/IMG/move_icon.png" }
ListElement{ name:qsTr("Delete"); urlImage: "qrc:/QmlContents/IMG/delete_folder.png" }
}
delegate: Button{
id:buttonLista
width: parent.width; height: listView.height/5
contentItem: Rectangle {
anchors.fill: parent; color: "transparent"
opacity: this.down ? 0.80 : 1
Rectangle{
width: parent.width; height: 1;
color: clrPaletta.lineTileContxMenu
anchors.bottom: parent.bottom;
visible: model.index < 4 ? true : false
}
Text {
id:testoItem
text: qsTr(name)
font.capitalization: Font.Capitalize; font.family: myVar.fontTile
color: clrPaletta.black; font.pixelSize: 18
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left; anchors.leftMargin: 65
}
Image {
id:imageList
source: urlImage
anchors.left: parent.left; anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
Just have a Item { id: overlay } that is last in main.qml, this way it is guaranteed to be on top of the rest of the content, and show up your popup parented to the overlay.
It will be better to have at most one of those at a time and centered in the screen for better user experience. You could however map the particular tile position to the screen to have the popup appear relative to it.
It will also be nice if the popup has an underlay that fills the "empty" area, so clicking outside of the popup closes it.
This means you won't have to bother with any manual z ordering whatsoever. Besides, it would only work for close siblings and such, good luck achieving the desired results in your use case...
Here is a quick example how you could reuse a single popup menu and have it connected to an arbitrary item to access its functionality:
Window {
visible: true
width: 600
height: 300
GridView {
id: view
model: 6
anchors.fill: parent
cellWidth: 200
cellHeight: 150
delegate: Rectangle {
id: dlg
width: 200
height: 150
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
function foo() { return index }
MouseArea {
anchors.fill: parent
onClicked: menu.item = dlg // to open the menu for this item
}
}
}
Item { // the overlay
anchors.fill: parent
visible: menu.item
MouseArea {
anchors.fill: parent
onClicked: menu.item = null // close the menu
}
Rectangle {
color: "black"
anchors.fill: parent
opacity: .5
}
Rectangle {
color: "white"
anchors.fill: menu
anchors.margins: -10
}
Column {
id: menu
anchors.centerIn: parent
property Item item: null
Button {
text: "index"
onClicked: console.log(menu.item.foo())
}
Button {
text: "color"
onClicked: console.log(menu.item.color)
}
}
}
}
You could try to create your context menu dynamically with SwipeView component set as parent:
var comp = Qt.createComponent("ContextMenuEditTile.qml");
var contextMenu = comp.createObject(view);
With this solution you do not need to struggle around with z-index values. At least when you use asynchonous Loader component the z-index will not work at all.
After creating the context menu you have to set your x and y values accordingly:
contextMenu.x = (your big switch case)
contextMenu.y = (your big switch case)
contextMenu.visible = true;
Read that first : http://doc.qt.io/qt-5/qml-qtquick-item.html#z-prop
the Z property order sibling items.
The problem here is only hierarchy, try to change your root, use rect or other instead of swipeview and make your swipeview and your button its childrens.
I need to scroll two or more list view at once using a single scrollBar. Initially, i used Column inside a Flickable but scroll was not happening as expected. Later, I used ListView and even that was not scrolling correctly.
So how to scroll a listview/layout content item with a scroll bar? Should I use ScrollView or Flickable or something else?
The stock scrollbar will only hook to a single scrollable item. However, it is trivial to make a custom scroller and hook multiple views to it:
Row {
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Rectangle {
id: scroller
width: 50
height: 50
color: "grey"
property real position: y / (main.height - 50)
MouseArea {
anchors.fill: parent
drag.target: parent
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
}
}
}
Note that it will work adequately even if the the views are of different content height, scrolling each view relative to the scroller position:
Realizing the question was not put that well, just in case someone wants to actually scroll multiple views at the same time comes around, I will nonetheless share another interesting approach similar to a jog wheel, something that can go indefinitely in every direction rather than having a limited range like a scrollbar. This solution will scroll the two views in sync until they hit the extent of their ranges. Unlike GrecKo's answer, this never leaves you with an "empty view" when the view size is different:
Row {
Flickable {
id: f1
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f1.contentY = Math.max(0, Math.min(f1.contentHeight - f1.height, f1.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
id: f2
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f2.contentY = Math.max(0, Math.min(f2.contentHeight - f2.height, f2.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
MouseArea {
id: jogger
width: 50
height: main.height
drag.target: knob
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
signal scroll(real p)
property real dy: 0
onPressed: dy = mouseY
onPositionChanged: {
scroll(dy - mouseY)
dy = mouseY
}
onScroll: console.log(p)
Rectangle {
anchors.fill: parent
color: "lightgrey"
}
Rectangle {
id: knob
visible: parent.pressed
width: 50
height: 50
color: "grey"
y: Math.max(0, Math.min(parent.mouseY - 25, parent.height - height))
}
}
}
Another advantage the "jog" approach has it is it not relative but absolute. That means if your view is huge, if you use a scroller even a single pixel may result in a big shift in content, whereas the jog, working in absolute mode, will always scroll the same amount of pixels regardless the content size, which is handy where precision is required.
You could just use a Flickable with your Columns.
I don't know how your Columns are laid out horizontally but if they are inside a Row it's pretty straightforward:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Multi Column")
Flickable {
anchors.fill: parent
contentWidth: row.implicitWidth
contentHeight: row.implicitHeight
Row {
id: row
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
ScrollBar.vertical: ScrollBar { }
}
}
Even if they are not in a Row you could do :
contentHeight: Math.max(column1.height, column2.height, ...)
Demonstration :