Qt Quick Components

Implementing multiselection support for ListView

You can use a ListView to set up a list with items that can be individually selected. The code given below demonstrates how to create a list that looks like this:

Creating the list view

The following code snippet is a basic definition for a ListView. A ListView has a model property which defines the data to be displayed, and a delegate property which defines how the data should be displayed on screen.

     ListView {
         id: listView
         anchors.fill: parent
         focus: true
         clip: true
         model: listModel
         delegate: listDelegate
     }

Creating the data model

The following code snippet defines a simple model for a multiselection list. It is implemented using a ListModel element and the items of the list are ListElements.

The important thing to note here is that each item in the list must include a data item to store the selection state of that item. In this example it is called selected. The delegate then uses this value to display the state visually to the user.

     ListModel {
         id: listModel
         ListElement {
             name: "Item 1"
             description: "Selectable item 1"
             selected: true
         }
         ListElement {
             name: "Item 2"
             description: "Selectable item 2"
             selected: false
         }
         ListElement {
             name: "Item 3"
             description: "Selectable item 3"
             selected: true
         }
         ListElement {
             name: "Item 4"
             description: "Selectable item 4"
             selected: false
         }
         ListElement {
             name: "Item 5"
             description: "Selectable item 5"
             selected: true
         }
     }

Creating the ListItem delegate

The final thing to do is to create the delegate. This defines how the data is displayed to the user and also passes information about data changes back to the model. Delegates are instantiated as needed by the system and can be destroyed at any time (even while scrolling the list) so it is not safe to store state information only in the delegate. You must make the delegate update the model whenever the state of a item changes. Then your state information does not disappear when the delegate item is destroyed.

The code snippet below defines a delegate with some texts and a checkbox. The ListView uses this delegate as a template to display the data for each item in the model onto the screen. Note that the onClicked() handler for toggling the checkbox is the handler for the whole list item rather than just the checkbox. The checkbox is a small target to touch, so a larger target is easier for the user. Also, the checkbox overlaps with the list's scroll area so it is hard to touch the checkbox without also touching the scroll area.

     Component {
         id: listDelegate

         ListItem {
             id: listItem

             // The texts to display
             Column {
                 anchors {
                     left:  listItem.padding.left
                     top: listItem.padding.top
                     bottom: listItem.padding.bottom
                     right: checkbox.left
                 }

                 ListItemText {
                     mode: listItem.mode
                     role: "Title"
                     text: name // Title text is from the 'name' property in the model item (ListElement)
                     width: parent.width
                 }

                 ListItemText {
                     mode: listItem.mode
                     role: "SubTitle"
                     text: description // SubTitle text is from the 'description' property in the model item
                     width: parent.width
                 }
             }

             // The checkbox to display
             CheckBox {
                 id: checkbox
                 checked: selected  // Checked state is from the 'selected' property in the model item
                 anchors { right: listItem.padding.right; verticalCenter: listItem.verticalCenter }
                 onClicked: listModel.set(index, { "selected": checkbox.checked })
             }

             // Handle a click (press and release) on the list item.
             onClicked: {
                 checkbox.checked = !checkbox.checked                    // Toggle the checkbox value
                 listModel.set(index, { "selected": checkbox.checked })  // Update the value of the 'selected' property in the appropriate model item.
             }
         }
     }