Delegate
Last updated
Last updated
When it comes to using models and views in a custom user interface, the delegate plays a huge role in creating a look and behaviour. As each item in a model is visualized through a delegate, what is actually visible to the user are the delegates.
Each delegate gets access to a number of attached properties, some from the data model, others from the view. From the model, the properties convey the data for each item to the delegate. From the view, the properties convey state information related to the delegate within the view. Let's dive into the properties from the view.
The most commonly used properties attached from the view are ListView.isCurrentItem
and ListView.view
. The first is a boolean indicating if the item is the current item, while the latter is a read-only reference to the actual view. Through access to the view, it is possible to create general, reusable delegates that adapt to the size and nature of the view in which they are contained. In the example below, the width
of each delegate is bound to the width
of the view, while the background color
of each delegate depends on the attached ListView.isCurrentItem
property.
If each item in the model is associated with an action, for instance, clicking an item acts upon it, that functionality is a part of each delegate. This divides the event management between the view, which handles the navigation between items in the view, and the delegate which handles actions on a specific item.
The most basic way to do this is to create a MouseArea
within each delegate and act on the onClicked
signal. This is demonstrated in the example in the next section of this chapter.
In some cases, the contents shown in a view changes over time. Items are added and removed as the underlying data model is altered. In these cases, it is often a good idea to employ visual cues to give the user a sense of direction and to help the user understand what data is added or removed.
Conveniently enough, QML views attach two signals, onAdd
and onRemove
, to each item delegate. By triggering animations from these, it is easy to create the movement necessary to aid the user in identifying what is taking place.
The example below demonstrates this through the use of a dynamically populated ListModel
. At the bottom of the screen, a button for adding new items is shown. When it is clicked, a new item is added to the model using the append
method. This triggers the creation of a new delegate in the view, and the emission of the GridView.onAdd
signal. The SequentialAnimation
called addAnimation
is started from the signal causes the item to zoom into view by animating the scale
property of the delegate.
When a delegate in the view is clicked, the item is removed from the model through a call to the remove
method. This causes the GridView.onRemove
signal to be emitted, starting the removeAnimation
SequentialAnimation
. This time, however, the destruction of the delegate must be delayed until the animation has completed. To do this, PropertyAction
element is used to set the GridView.delayRemove
property to true
before the animation, and false
after. This ensures that the animation is allowed to complete before the delegate item is removed.
A commonly used mechanism in lists is that the current item is expanded when activated. This can be used to dynamically let the item expand to fill the screen to enter a new part of the user interface, or it can be used to provide slightly more information for the current item in a given list.
In the example below, each item is expanded to the full extent of the ListView
containing it when clicked. The extra space is then used to add more information. The mechanism used to control this is a state expanded
that each item delegate can enter, where the item is expanded. In that state, a number of properties are altered.
First of all, the height
of the wrapper
is set to the height of the ListView
. The thumbnail image is then enlarged and moved down to make it move from its small position into its larger position. In addition to this, the two hidden items, the factsView
and closeButton
are shown by altering the opacity
of the elements. Finally, the ListView
is setup.
Setting up the ListView
involves setting the contentsY
, that is the top of the visible part of the view, to the y
value of the delegate. The other change is to set interactive
of the view to false
. This prevents the view from moving. The user can no longer scroll through the list or change the current item.
As the item first is clicked, it enters the expanded
state, causing the item delegate to fill the ListView
and the contents to rearrange. When the close button is clicked, the state is cleared, causing the delegate to return to its previous state and re-enabling the ListView
.
The techniques demonstrated here to expand the delegate to fill the entire view can be employed to make an item delegate shift shape in a much smaller way. For instance, when browsing through a list of songs, the current item could be made slightly larger, accommodating more information about that particular item.