aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/doc/src/dynamicview-tutorial.qdoc
blob: 0b5f2b4f604d4ddd9926608b3c8307da2688d328 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.  Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: http://www.gnu.org/copyleft/fdl.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
\page qml-dynamicview-tutorial.html tutorial
\inqmlmodule QtQuick 2
\title QML Dynamic View Ordering Tutorial
\brief A tutorial describing how to re-arrange items in a QML ListView
\nextpage QML Dynamic View Ordering Tutorial 1 - A Simple ListView and Delegate

This tutorial shows how items in a ListView can be re-ordered without modifying the source model.
It demonstrates using drag and drop to reposition individual items within a view and using model
data to dynamically sort all items in a view.

Tutorial chapters:

\list 1
\li \l {tutorials/dynamicview/dynamicview1}{A Simple ListView and Delegate}
\li \l {tutorials/dynamicview/dynamicview2}{Dragging View Items}
\li \l {tutorials/dynamicview/dynamicview3}{Moving Dragged Items}
\li \l {tutorials/dynamicview/dynamicview4}{Sorting Items}
\endlist

All the code in this tutorial can be found in Qt's \c examples/tutorials/dynamicview
directory.
*/

/*!
\page qml-dynamicview-tutorial1.html
\inqmlmodule QtQuick 2
\title QML Dynamic View Ordering Tutorial 1 - A Simple ListView and Delegate
\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial
\nextpage QML Dynamic View Ordering Tutorial 2 - Dragging View Items

\example tutorials/dynamicview/dynamicview1

We begin our application by defining a ListView, a model which will provide data to the view, and a
delegate which provides a template for constructing items in the view.

The code for the ListView and delegate looks like this:

\snippet tutorials/dynamicview/dynamicview1/dynamicview.qml 0

The model is defined in a separate QML file which looks like this:

\snippet tutorials/dynamicview/dynamicview1/PetsModel.qml 0
\snippet tutorials/dynamicview/dynamicview1/PetsModel.qml 1

\section2 Walkthrough

The first item defined within the application's root Rectangle is the delegate Component.  This
is the template from which each item in the ListView is constructed.

The \c name, \c age, \c type, and \c size variables referenced in the delegate are sourced from
the model data.  The names correspond to roles defined in the model.

\snippet tutorials/dynamicview/dynamicview1/dynamicview.qml 1

The second part of the application is the ListView itself to which we bind the model and delegate.

\snippet tutorials/dynamicview/dynamicview1/dynamicview.qml 2
*/

/*!
\page qml-dynamicview-tutorial2.html
\inqmlmodule QtQuick 2
\title QML Dynamic View Ordering Tutorial 2 - Dragging View Items
\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 1 - A Simple ListView and Delegate
\nextpage QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items

\example tutorials/dynamicview/dynamicview2

Now that we have a visible list of items we want to be able to interact with them. We'll start
by extending the delegate so the visible content can be dragged up and down the screen.  The
updated delegate looks like this:

\snippet tutorials/dynamicview/dynamicview2/dynamicview.qml 0

\section2 Walkthrough

The major change here is the root item of the delegate is now a MouseArea which provides handlers
for mouse events and will allow us to drag the delegate's content item.  It also acts as
a container for the content item which is important as a delegate's root item is positioned by
the view and cannot be moved by other means.

\snippet tutorials/dynamicview/dynamicview2/dynamicview.qml 1
\snippet tutorials/dynamicview/dynamicview2/dynamicview.qml 2

Dragging the content item is enabled by binding it to the MouseArea's
\l {QtQuick2::MouseArea::drag.target}{drag.target} property.  Because we still want the view to be
flickable we wait until the MouseArea's \l {QtQuick2::MouseArea::onPressAndHold}{onPressAndHold}
handler is triggered before binding the drag target. This way when mouse moves before the hold
timeout has expired it is interpreted as moving the list and if it moves after it is interpreted as
dragging an item.  To make it more obvious to the user when an item can be dragged we'll change the
background color of the content item when the timeout has expired.

\snippet tutorials/dynamicview/dynamicview2/dynamicview.qml 3

The other thing we'll need to do before an item can be dragged is to unset any anchors on the
content item so it can be freely moved around.  We do this in a state change that is triggered
when the delegate item is held, at the same time we can reparent the content item to the root item
so that is above other items in the stacking order and isn't obscured as it is dragged around.

\snippet tutorials/dynamicview/dynamicview2/dynamicview.qml 4

*/

/*!
\page qml-dynamicview-tutorial3.html
\inqmlmodule QtQuick 2
\title QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items
\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 2 - Dragging View Items
\nextpage QML Dynamic View Ordering Tutorial 4 - Sorting Items

\example examples/tutorials/dynamicview/dynamicview3

The next step in our application to move items within the list as they're dragged so that we
can re-order the list.  To achieve this we introduce three new elements to our application;
VisualDataModel, \l Drag and DropArea.

\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 0
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 1
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 2
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 5

\section2 Walkthrough

In order to re-order the view we need to determine when one item has been dragged over another. With
the Drag attached property we can generate events that are sent to the scene graph whenever the item
it is attached to moves.

\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 1

Drag events are only sent while the active property is true, so in this example the first event
would be sent when the delegate was held with additional event sents when dragging.  The
\l {QtQuick2::Drag::hotSpot}{hotSpot} property specifies the relative position of the drag events
within the dragged item, the center of the item in this instance.

Then we use a DropArea in each view item to determine when the hot spot of the dragged item
intersects another item, when a drag enters one of these DropAreas we can move the dragged item
to the index of the item it was dragged over.

\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 3

To move the items within the view we use a VisualDataModel.  The VisualDataModel element is used by
the view elements to instantiate delegate items from model data and when constructed explicitly can
be used to filter and re-order the model items provided to ListView.  The
\l {QtQuick2::VisualDataModel::items}{items} property of VisualDataModel provides access to the
view's items and allows us to change the visible order without modifying the source model.  To
determine the current visible index of the items we use \l {QtQuick2::VisualDataModel::itemsIndex}
{itemsIndex} property on the VisualDataModel attached property of the delegate item.

To utilize a VisualDataModel with a ListView we bind it to the \l {QtQuick2::ListView::model}{model}
property of the view and bind the \l {QtQuick2::VisualDataModel::model}{model} and
\l {QtQuick2::VisualDataModel::delegate}{delegate} to the VisualDataModel.

\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 4

*/

/*!
\page qml-dynamicview-tutorial4.html
\inqmlmodule QtQuick 2
\title QML Dynamic View Ordering Tutorial 4 - Sorting Items
\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items

\example tutorials/dynamicview/dynamicview4

Drag and drop isn't the only way items in a view can be re-ordered, using a VisualDataModel it is
also possible to sort items based on model data.  To do that we extend our VisualDataModel instance
like this:

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 0

\section2 Walkthrough

Items in a VisualDataModel are filtered into groups represented by the VisualDataGroup type,
normally all items in the model belong to a default \l {QtQuick2::VisualDataModel::items}{items}
group but this default can be changed with the includeByDefault property.  To implement our sorting
we want items to first be added to an unsorted group from where we can transfer them to a sorted
position in the items group.  To do that we clear includeByDefault on the items group and set it on
a new group name 'unsorted'.

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 1
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 2

We sort the items by first finding the position in the items group to insert the first unsorted
item and then transfer the item to the items group before moving it to the pre-determined index and
repeat until the unsorted group is empty.

To find the insert position for an item we request a handle for the item from the unsorted group
with the \l {QtQuick2::VisualDataModel::get} {get} function.  Through the model property on this
handle we can access the same model data that is available in a delegate instance of that item and
compare against other items to determine relative position.

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 3

The lessThan argument to the sort function is a comparsion function which will determine the order
of the list.  In this example it can be one of the following:

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 4

A sort is triggered whenever new items are added to the unsorted VisualDataGroup which we are
notified of by the \l {QtQuick2::VisualDataGroup::onChanged}{onChanged} handler.  If no sort
function is currently selected we simply transfer all items from the unsorted group to the items
group, otherwise we call sort with the selected sort function.

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 5

Finally when the selected sort order changes we can trigger a full re-sort of the list by moving
all items from the items group to the unsorted group, which will trigger the
\l {QtQuick2::VisualDataGroup::onChanged}{onChanged} handler and transfer the items back to the
items group in correct order.  Note that the \l {QtQuick2::VisualDataGroup::onChanged}{onChanged}
handler will not be invoked recursively so there's no issue with it being invoked during a sort.

\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 6

*/