How to get index of particular item in ListModel? - qt

I've got a little problem with GridView component. I have to change some property of some objects during runtime. To do this, I can use the setProperty() function. However, this function needs index to work. And here the problem appears becouse, all items are created during runtime.
How can I get index of specific item?
Let me explain a little bit more. The item I'm reffering to is just a simple rectangle with MouseArea. Here's its code :
Rectangle {
property var colorR
id: namE
width: 100
height: 100
color: colorR
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked:
{
console.log(parent.nameIndex)
}
}
}
And here is my GridView code :
GridView {
id: gridView1
anchors.rightMargin: 5
anchors.leftMargin: 5
anchors.bottomMargin: 5
anchors.topMargin: 10
anchors.fill: parent
flickableDirection: Flickable.VerticalFlick
snapMode: GridView.NoSnap
highlightRangeMode: GridView.NoHighlightRange
highlightMoveDuration: 148
flow: GridView.FlowLeftToRight
layoutDirection: Qt.RightToLeft
model: ListModel {id: listModelMy}
delegate: Column {ColorBlock{}}
cellHeight: 100
cellWidth: 100
}
And here is my code to dynamicly create items in GridView
Rectangle {
id: addButton
width: 65
height: 55
color: "#b04b4b"
border.color: "#252323"
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
anchors.right: parent.right
anchors.rightMargin: 8
Image {
id: image1
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.bottomMargin: 10
anchors.topMargin: 10
anchors.fill: parent
source: "svgIcons/add.svg"
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked:
{
var test = listModelMy.append(ListElement);
}
}
}
}
I don't really know how to get this index. Or I'm just blind and I'm missing something obvious.

There is an index attached property available for use inside the delegate. For every delegate instance it will correspond to the associated list model element index.
GridView {
anchors.fill: parent
model: ListModel { id: mod }
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
text: index
anchors.centerIn: parent
}
}
}

Related

Qt5 QML: swap two Items in ListView

i'm using model view in qml.
ListView{
id: targetParameter
width: parent.width
height: parent.height
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: 20
spacing: 10
orientation: ListView.Horizontal
interactive: false
model: proxyModelCharacterization
delegate: ParameterChangeTarget {
paramWidht: {
if(name === "NAME"){
targetParameter.width * 0.11
}else{
targetParameter.width * 0.42
}
}
paramHeight: targetParameter.height * 0.95
}
}
with this list view, I have three elements (for example Rectangle).
rect1, rect2, rect3.
i want to swap rect2 and rect3, but i can't change the order in which they are instantiated on my controller.
how can i swap two element on list view?
every kind of help or suggestion are greatly appreciated.
You can use the .move() method to move an element in a ListModel.
In the following example, the elements are added in the ListModel once, in the Component.onCompleted signal. You can then move them up or down (in the model and hence, the view) by clicking on the corresponding buttons. The buttons use the move() method of ListModel.
Example:
ListModel {
id: listModel
}
ListView {
id: listView
anchors.fill: parent
spacing: 10
model: listModel
delegate: Rectangle {
height: btnMoveUp.height
width: listView.width
color: "red"
Button {
id: btnMoveUp
anchors.left: parent.left
text: "Move Up"
enabled: index !== 0
onClicked: listModel.move(index, index-1,1)
}
Button {
id: btnMoveDown
anchors.left: btnMoveUp.right
text: "Move Down"
enabled: index !== listModel.count - 1
onClicked: listModel.move(index, index+1,1)
}
Text {
anchors {
left: btnMoveDown.right
right: parent.right
verticalCenter: parent.verticalCenter
}
text: model.name
}
}
}
Component.onCompleted: {
listModel.append({name: "Item 1"});
listModel.append({name: "Item 2"});
listModel.append({name: "Item 3"});
listModel.append({name: "Item 4"});
listModel.append({name: "Item 5"});
}

How do I scroll to the last item in a Flickable's Repeater

I have a Flickable that is holding two Repeaters with a column layout. I am hoping to scroll to the last item in the first repeater. Is this possible?
I suppose one way could be to count how many items are in the first repeater and then multiply that by the height of the delegate I am using. (The delegate is a fixed height.) Or take the height of the repeater and subtract the height of the last delegate. etc... Though I am hoping on a better way than this.
import QtQuick 2.7
import QtQuick.Controls 2.0
Item {
id:passwordsView
Flickable {
id: flickable1
anchors.fill: parent
contentHeight: passwordsView_column.height
ScrollBar.vertical: ScrollBar { }
Column {
id:passwordsView_column
spacing: 15
anchors.left: parent.left
anchors.right: parent.right
Repeater {
id: passwordsView_breadcrumb
anchors.left: parent.left
anchors.right: parent.right
model: BreadcrumbModel {}
delegate: PasswordFolderDelegate {
y: 8;
anchors.left: parent.left;
anchors.right: parent.right;
}
}
Repeater {
id: passwordsView_contents
model: PasswordModel {}
PasswordFolderDelegate {
y: 8
anchors.left: parent.left
anchors.right: parent.right
}
anchors.left: parent.left
anchors.right: parent.right
}
}
}
}
Or take the height of the repeater and subtract the height of the last delegate.
Repeater doesn't have a height, as it merely positions the items, so that might be a little difficult.
The easiest approach I can think of is to use mapToItem():
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
width: 400
height: 400
visible: true
Flickable {
id: flickable1
anchors.fill: parent
contentHeight: passwordsView_column.height
ScrollBar.vertical: ScrollBar { }
Column {
id:passwordsView_column
spacing: 15
anchors.left: parent.left
anchors.right: parent.right
Repeater {
id: passwordsView_breadcrumb
anchors.left: parent.left
anchors.right: parent.right
model: 10
delegate: Rectangle {
width: 50
height: 50
color: "transparent"
border.color: "salmon"
Text {
text: index
anchors.centerIn: parent
}
}
}
Repeater {
id: passwordsView_contents
model: 10
delegate: Rectangle {
width: 50
height: 50
color: "transparent"
border.color: "#444"
Text {
text: index
anchors.centerIn: parent
}
}
}
}
}
Button {
text: "Position at end"
anchors.top: parent.top
anchors.right: parent.right
onClicked: {
var lastItem = passwordsView_breadcrumb.itemAt(passwordsView_breadcrumb.count - 1);
flickable1.contentY = lastItem.mapToItem(flickable1.contentItem, 0, 0).y
}
}
}
Note that this makes the view move instantly. If you want smooth scrolling, you'll probably have to calculate the required velocity somehow and pass it to flick().

How to make a horizontal pagination?

I'm developing a BlackBerry 10 mobile application using the Momentics IDE 2.1.2 (native SDK).
I'm looking for a sample that shows how to build a horizontal pagination like in the image below that I will put it inside a container replacing with that a listview with a grid display.
Can anyone help me with this ?
You can easy build simple pagination using ListView only. Hope the example below will be usefull:
import QtQuick 2.4
Item {
width: 600
height: 800
ListView {
id: listView
anchors.fill: parent
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
highlightRangeMode: ListView.StrictlyEnforceRange
model: 5
clip: true
delegate: Rectangle {
width: listView.width
height: listView.height
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1);
Text {
anchors.centerIn: parent
text: "page " + index
}
}
}
Item {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 30
Row {
anchors.centerIn: parent
Repeater {
model: listView.model
Rectangle {
width: 20
height: 20
border.width:2
border.color: "white"
color: index == listView.currentIndex ? "orange" : "white"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
}

QML: Using ScrollView leads to incorrect displaying of elements

I'm using Qt 5.2.1 for windows (Qt creator 3.0.1)
I have a custom QML component, it works fine when I'm loading in into rectangle:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: mainRectangle
anchors.fill: parent
Loader {
anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld01;
onLoaded: {
ld01.visible = true;
anchors.top = parent.top;
}
}
Loader {
anchors.top: ld01.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld02;
onLoaded: {
anchors.top = ld01.bottom;
ld02.visible = true;
}
}
Component.onCompleted: {
ld01.setSource("View_item2.qml");
ld02.setSource("View_item2.qml");
}
}
But when I'm trying to put it all inside a ScrollView, elements of my component are moved somewhere. What kind of trick I should implement for correct use of ScrollView?
ScrollView {
id: mainTabLayout
anchors.fill: parent
anchors.margins: 4
//here I put a code from above (except imports, of course)
}
Component code is below:
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0
Rectangle {
id: slv_layout
objectName: "itemColumnLayout"
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 1
property int minimal_height: 200
height: 400
color: "green"
MouseArea {
property bool is_pressed: false
property int initial_y: 0
property int proposed_y: 0
id: resizeStick
enabled: true
anchors.bottom: parent.bottom
height: 10
width: parent.width
hoverEnabled: true
onEntered: {
cursorShape = Qt.SizeVerCursor;
}
onPressed: {
is_pressed = true;
initial_y = mouseY;
}
onReleased: {
is_pressed = false;
}
onMouseYChanged: {
if (is_pressed) {
proposed_y = slv_layout.height + mouseY - initial_y;
if (proposed_y >= slv_layout.minimal_height) {
slv_layout.height += (mouseY - initial_y);
initial_y = mouseY;
}
}
}
}
Text {
id: slvTitle
text: "device name"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Rectangle {
anchors.top: slvTitle.bottom
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.topMargin: 2
color: "blue"
Button {
id: slv_butt_run;
objectName: "slv_butt_run"
width: 60
height: width
text: "Run"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_settings;
objectName: "slv_butt_settings"
width: 60
height: width
text: "Settings"
anchors.top: parent.top
anchors.left: slv_butt_run.right
anchors.margins: 2
}
Button {
id: slv_butt_stop;
objectName: "slv_butt_stop"
width: 60
height: width
text: "Stop"
anchors.top: slv_butt_run.bottom
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_expand;
objectName: "slv_butt_expand"
width: 60
height: width
text: "Expand"
anchors.top: slv_butt_settings.bottom
anchors.left: slv_butt_stop.right
anchors.margins: 2
}
TextArea {
id: slv_log_area
anchors.left: slv_butt_expand.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 3
}
}
}
How it looks when all is ok:
How it looks when not ok:
Actually, I still don't know, why code works as described above. But I have found acceptable method to solve task other way.
Looks like "put a needle into egg, egg into duck, duck into rabbit":
ScrollView must contain a ListView component which has a corresponding ListModel and a custom component should act as delegate. Only with ListModel I've got correct automatic scrolling and relative emplacement support.
ScrollView {
id: id_scrollView
anchors.fill: parent
objectName: "ScrollView"
frameVisible: true
highlightOnFocus: true
style: ScrollViewStyle {
transientScrollBars: true
handle: Item {
implicitWidth: 14
implicitHeight: 26
Rectangle {
color: "#424246"
anchors.fill: parent
anchors.topMargin: 6
anchors.leftMargin: 4
anchors.rightMargin: 4
anchors.bottomMargin: 6
}
}
scrollBarBackground: Item {
implicitWidth: 14
implicitHeight: 26
}
}
ListView {
id: id_listView
objectName: "ListView"
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 11
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
delegate: view_component
model: id_listModel
ListModel {
id :id_listModel
objectName: "ListModel"
}
//delegate: View_item2.Item
Component {
id: view_component
View_item2 {
objectName: name
}
}
}
According to the ScrollView documentation,
A ScrollView can be used either to replace a Flickable or decorate an existing Flickable. ... The width and height of the child item will be used to define the size of the content area.
A ScrollView needs to know two width-height pairs: the first one is the width and height used to display the region, and the second one is the width and height of the content. If the area of the content is larger than the display area, the display area will add a scroll bar on it.
In your example:
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
anchors.fill: parent
//...
}
}
The width and height of the content is bound to the display area, making the two areas be in the same size. The width and height of display area is the one in mainTabLayout, which is bound to it's parent; and the width and height of the content is the one in mainRectangle, which is bound to it's parent, mainTabLayout. Therefore the ScrollView cannot work correctly since ScrollView expects the two values are different, not bound together.
To solve your problem, you can explicitly assign width and height to mainRectangle. Do not bind the width and height of mainRectangle to it's parent using anchors.fill:parent.
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
width: 800; height: 800 //not binding to parent.width & height
//...
}
}
And this can work correctly.

Nested ScrollView in QML doesn't respond to mousewheel

I have a nested ScrollView, similar to the following QML:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
width: 200
height: 600
ScrollView {
id: sView
anchors.fill: parent
ListView {
id: list
boundsBehavior: Flickable.StopAtBounds
clip: true
focus: true
interactive: true
model: 5
delegate: Component {
MouseArea {
id: hoverArea
width: 100
height: 200
onClicked: list.currentIndex = index;
Rectangle {
id: fauxParent
anchors.fill: parent
border.width: 1
border.color: "black"
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
height: parent.height
width: parent.width / 2
border.width: 1
border.color: "purple"
color: "green"
Text {
anchors.centerIn: parent
text: "stuff"
}
}
ScrollView {
//parent: sView
anchors.top: fauxParent.top
anchors.right: fauxParent.right
height: fauxParent.height
width: fauxParent.width / 2
ListView {
model: 3
delegate: Component {
Rectangle {
radius: 10
height: 100
width: 100
color: "blue"
}
}
}
}
}
}
}
}
}
}
It seems to run correctly, except that the inner ScrollView won't respond to the mousewheel: the outer ScrollView intercepts that event. The only fix I've found in research for this, is to set the inner scrollview's parent directly to the outer scrollview (uncomment the parent: sView line). Unfortunately, this re-positions all five scrollview delegates onto the top right corner of the outer scrollview. It seems that ScrollView positions itself based on its parent?
For the record, my actual application is wrapping a large section of the page in a scrollview so as to allow the user to access sections of it that may be out of bounds for the current window size. The content of this section, though, has a variety of different controls for a variety of different purposes, including some scrollviews. So I'd also accept an alternate way of moving around a set of generic content that's too large for the window.
This is a Windows desktop app, so I don't need to consider mobile-specific issues.
You nested four elements that handle scroll Events.
Why do you put a ScrollView arround a ListView?
If you remove the ScrollViews the Mousewheel work fine.
Rectangle {
width: 200
height: 600
ListView {
anchors.fill: parent
id: list
boundsBehavior: Flickable.StopAtBounds
clip: true
focus: true
interactive: true
model: 5
delegate: Component {
MouseArea {
id: hoverArea
width: 100
height: 200
onClicked: list.currentIndex = index;
Rectangle {
id: fauxParent
anchors.fill: parent
border.width: 1
border.color: "black"
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
height: parent.height
width: parent.width / 2
border.width: 1
border.color: "purple"
color: "green"
Text {
anchors.centerIn: parent
text: "stuff"
}
}
ListView {
anchors.top: fauxParent.top
anchors.right: fauxParent.right
height: fauxParent.height
width: fauxParent.width / 2
model: 3
delegate: Component {
Rectangle {
radius: 10
height: 100
width: 100
color: "blue"
}
}
}
}
}
}
}
}
If you miss the Scrollbar look at this:
How to create scrollbar in QtQuick 2.0?

Resources