I am adding Image objects dynamically to a GridLayout in a QML file in qt. I want to position the image items so that each new image item comes to the right side of the previous one and if there is no place in that row, it is placed directly to the next row. It is exactly the way how I typed this question, i.e. letters are my image items and text box is the layout.
However the output is following:
The layout leaves space between items as seen in the screenshot. I've read through the properties of gridlayout and tried many combinations out but didn't come up with the right combination. These are the properties I set so far:
GridLayout {
id: myLayout
anchors.fill: parent
columnSpacing: preferredColumnSpacing
rowSpacing: preferredRowSpacing
Component {
id: myImageComponent
Image {
visible: true
Layout.alignment: (Qt.AlignLeft | Qt.AlignTop)
Layout.preferredWidth: preferredImageWidth
Layout.preferredHeight: preferredImageHeight
}
}
}
Which modification gives me the expected behaviour?
Edit: in the screenshot above, the layout has 9 columns, 4 rows but 17 image items.
Related
I have a ListView (horizontal orientation) in my qml containing some fixed-size elements. I want items to be spaced out to fill the entiew width of ListView element. So if there are less elements I want them to be spaced out more. Basically what I need is exactly like Layout.fillWidth = true property of RowLayout but for ListView.
I can count how many items I have, then subtract total items width from ListView width, divide by items count and assign the spacing but it seems too silly to do.
Is there a way to do this automatically like in RowLayout?
Or maybe I need to use something different from ListView for this? Something like RowLayout but that I can assign my list data model to?
You can accomplish what you want with a ListView, you just need to adjust the spacing dynamically based on how many delegates you have. This example will break down if your delegates are differently-sized (as this is based only on the width of the first delegate), or if the delegates cumulatively exceed the width of the ListView.
ListView {
width: 500
orientation: Qt.Horizontal
model: 6
spacing: {
if (count > 0) {
return (width - (itemAtIndex(0).width * count))/(count - 1)
} else {
return 0
}
}
delegate: Rectangle {
implicitHeight: 50
implicitWidth: 50
color: "red"
border.width: 1
}
}
ListView may not be the most appropriate container for this task. I say this because it has a built in ScrollView and other behaviors that it sounds like you don't need. If all you need is a simple row of a few identically-sized delegates, I agree with scopchanov and believe that a Repeater inside a RowLayout would be the best option. Here is a simple example:
RowLayout {
width: 500
Repeater {
model: 6
delegate: Rectangle {
implicitHeight: 50
implicitWidth: 50
color: "tomato"
border.width: 1
Layout.alignment: Qt.AlignHCenter // must be set to align the rectangles within their empty space
}
}
}
You may notice that this introduces gaps to the left and right, if these gaps are unacceptable, you may need to set the spacing on the RowLayout in the same manner as the ListView example instead.
I have the following horizontal list:
BulletsListDelegate.qml
import QtQuick 2.0
Rectangle {
width: 8
height: 8
color: "#808080"
radius: width * 0.5
}
main.qml
import QtQuick 2.0
Item {
width: 256
height: 256
ListModel {
id: bulletsListModel
ListElement {
a: 'example'
}
ListElement {
a: 'example'
}
...
}
ListView {
id: bulletsList
spacing: 8
orientation: ListView.Horizontal
delegate: BulletsListDelegate {}
model: bulletsListModel
anchors.bottom: parent.bottom
width: parent.width
}
}
And the elements are shown like this (they are the grey bullets)
I want them to show in the horizontal center of the black box above them (its parent).
Is there any form of centralize or justify the items of the list?
So, if I understand your question correctly, you want to have alignment for instances of your items in a ListView. Using a ListView, that is not so easy to achieve. If you have an uneven number of items, you can do it by using preferredHighlightBegin and preferredHighlightEnd to have a 1-item sized region in the center of your ListView, and then setting hightlightRangeMode to ListView.StrictlyEnforceRange. You can set the currentIndex to point to index so that the middle item will be considered current. That puts it within the range you defined, and thus in the center. That does not work when you have an even number of items though, so it's a hack with limited value.
My question is: do the items have to be positioned using a ListView? It looks like you don't actually need much of the functionality of the ListView at all? If you don't need the other features from ListView (like scrolling), you can just use a Repeater instead. That allows you to simply put the items in a Row positioner, which you can width of count*(delegateWidth+spacing)-spacing and a height equal to your delegate height. Then, you can use acnhors to position the Row centered to whatever you like.
André's answer suggested me to use Repeater and Rows instead of ListView, and it completely solved my problem. But... didn't find a way to align an actual ListView yet.
Row {
spacing: 8
Repeater {
id: bulletsRepeater
model: 5
BulletsDelegate { }
}
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
I want to display a large amount of content, for example, a grid of multiple images inside a window that is smaller than the content, similar to a geographical map but instead of a map, I want my own components as the "map". For this minimal working example, let's take for the content a grid of images with a total size of 1000x1000 with a window into this content of only 300x300.
I have tried 2 different approaches, but I will only go into detail of the first approach as that is the one that got me closest to my desired result:
I have tried the Flickable component but the content cannot be moved outside the predefined bounds, making the user unable to move the view in order to display all the parts of the content. So the simplest solution that I'm thinking about now is if I could remove these bounds from the Flickable component, but how?
I have also tried the Map component but it requires a "plugin" and I was unable to figure out how to use this component with my own content of an image grid.
The content that I want to show is something this
Grid {
columns: 5
spacing: 2
Repeater {
model: ListModel {
ListElement {
path: 'test1'
}
ListElement {
path: 'test2'
}
// ...
ListElement {
path: 'test25'
}
}
Rectangle {
width: 200
height: 200
Image {
anchors.fill: parent
source: 'file:' + path
}
}
}
}
I tried, putting this inside the Flickable like this
Flickable {
anchors.centerIn: parent
width: 300
height: 300
contentWidth: 1000
contentHeight: 1000
clip: true
// INSERT CUSTOM GRID COMPONENT HERE
}
This results in a 300x300 view inside the content as expected, but once you start to flick through the content to view different parts of it, you are stopped by the bounds preventing you from seeing anything outside these bounds. You can see it while dragging but once you release the view of the content is reset to these bounds.
So how do I remove these bounds? (Or is there a different component more suitable for my application?)
Here is a gif that shows how the content can be dragged passed the bounds, but once released it will only go up to the bounds and not further
I found the issue, I set the contentWidth and contentHeight of the Flickable incorrectly, this example works fine. The contentWidth and contentHeight determine the bounds in which you can flick.
I want to have two list views followed by one another in a big ScrollView, say because they have slightly different delegates. So a layout is like this:
Unfortunately ListView type is also a flickable, so it doesn't present all its content in a flat list suitable for having inside a scroll view.
So how do I do this with Qt Quick views?
I've tried a trick: I can resize list views like this:
ListView {
id: list1
height: contentHeight + spacing * count
model: superModel
delegate: delegate1
}
Unfortunately, aside from being a dirty hack and leaving an unneccesary flickable grabbing my clicks, it doesn't really work: content just doesn't fit as there are still top and bottom margins I don't know the value of.
You should use a ColumnLayout with two Repeater's in a ScrollView (or Flickable if you like)
ScrollView {
contentWidth: width //maybe you don't need this
ColumnLayout {
width: parent.width //maybe you don't need this
Repeater {
model: superModel1
delegate: delegate1
}
Repeater {
model: superModel2
delegate: delegate2
}
}
}
Since you didn't show the delegate, you might need minor tweaking of implicitHeight and/or implicitWidth.
In the picture Test, Test 1 and Test 2 are in the ListView. In this case Test element is highlighted. How can I modify view behavior to ensure that current (highlighted) item stays always in the middle of the list? What I want to achieve is represented in the following picture:
You just need highlightRangeMode with preferredHighlightBegin and preferredHighlightEnd. From the documentation:
These properties affect the position of the current item when the list is scrolled. For example, if the currently selected item should stay in the middle of the list when the view is scrolled, set the preferredHighlightBegin and preferredHighlightEnd values to the top and bottom coordinates of where the middle item would be. If the currentItem is changed programmatically, the list will automatically scroll so that the current item is in the middle of the view. Furthermore, the behavior of the current item index will occur whether or not a highlight exists.
Here is a full example of an horizontal ListView with the current item positioned at the center.
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
width: 300
height: 150
visible: true
ListView {
anchors.fill: parent
spacing: 5
model: 20
delegate:
Rectangle {
width: 30
color: ListView.view.currentIndex === index ? "red" : "steelblue"
height: ListView.view.height
Text {
anchors.centerIn: parent
text: index
font.pixelSize: 20
}
}
orientation: Qt.Horizontal
preferredHighlightBegin: 150 - 15
preferredHighlightEnd: 150 + 15
highlightRangeMode: ListView.StrictlyEnforceRange
}
}
You could have a look at ListView's positionViewAtIndex method and see if that helps.