Skip to content
nucularmoo edited this page May 28, 2018 · 9 revisions

Basic Delegate (P0 | 1h)

Explanation of the contents of a topic page @ Topic reference page

Back to Week 3

Objective: OBJECTIVE

Tino: Rendering and editing model data

Beginner

  • What is the model/view pattern? (3.00)

Intermediate

  • What is a delegate? Done
  • When are delegates used? Done?
  • How do delegates relate to the model/view pattern? Done
  • How is data provided to the delegate? Done
  • What views are available to delegates? Done ?
  • How to modify data from the delegate Done ?

Omitted

  • What is QAbstractItemDelegate?
  • What is QItemDelegate?

Tino: Attached properties. This is very important. How to use the attached properties, provided by views to delegates? They are visible to the root of the delegate only, so this is also important thing to mention. There could be trivial examples, such as currentItem but also Path attributes in the path view provides visually nice examples.

K: Attached properties are ListView.delayRemove, ListView.isCurrentItem, ListView.view and ListView.section stuff

Expert

Omitted


Course material content

Contrary to other Model-View frameworks where the View can be both responsible of displaying the data items and handling user interaction, Qt uses the delegate concept to separate these responsibilities from the View. This allows flexibility in the way how user input is obtained, and how the view is painted. In short, the delegate sits between the model and the view and handles the interaction between the two.

As we have briefly discussed earlier, delegates act as templates for instantiating the visual items inside the view. We bind the data roles provided by the model to visual item properties, such as the Text.text or Image.source property. Delegates can also be used to modify and update the data bound to the roles. In this example, we have a TeamDelegate that updates the bound data when clicked:

ListModel {
    id: teamModel
    ListElement {
        teamName: "Team C++"
        teamColor: "blue"
    }
}

ListView {
    anchors.fill: parent
    model: teamModel
    delegate: TeamDelegate {}
}

// TeamDelegate.qml
Component {
    Text {
        text: teamName
        color: teamColor

        MouseArea {
            anchors.fill: parent
            onClicked: {
                    model.teamName = "Team Quick"
                    model.teamColor = "red"
                }
            }
        }
    }
}

Within the delegate, we have access to the data roles as internal properties. We also have the property model available to us, which can be used to access the roles without naming conflicts.

Interacting with the view and the model

Until now, we have been modifying and accessing the item data provided for us. but how can the delegate access the view or the model without depending on a certain id (ie. inside a Component file)?

We are in luck, as we have access to the bound view from within the delegate through the attached properties with for example ListView.view, GridView.view or PathView.view. Note: these properties are only attached to the root of delegate object, not to any child objects. Read more about the semantics of attached properties here.

As the ListView.view contains the view, we can access the underlying model through the ListView.view.model property. Any defined properties and signals within the view are also accessible. This is very useful if you want to reuse the same delegate for multiple views, but want a visual feature to be different for each type of view. Thus we are no longer dependent on any specific view or model.

Here we have the properties quality and color in our ListModel and ListView respectively. Notice how we need to access the properties through the root object team.

ListModel {
    id: teamModel

    property string quality: "good"

    ListElement {
        teamName: "Team C++"
    }
}

ListView {
    anchors.fill: parent

    property string color: "purple"

    model: teamModel
    delegate: TeamDelegate {}
}

// TeamDelegate.qml
Component {
    Row {
        id: team
        spacing: 2

        Text {
            text: model.teamName
            color: team.ListView.view.color
        }

        Text {
            text: "Quality: " + team.ListView.view.model.quality
        }
    }
}

In most of the views, like ListView, we have the attached property of ListView.isCurrentItem that can be used to change the appearance of the currently selected item:

// ContactsDelegate.qml
Component {
    id: contactsDelegate
    Rectangle {
        id: wrapper
        width: 180
        height: contactInfo.height
        color: ListView.isCurrentItem ? "black" : "red"
        Text {
            id: contactInfo
            text: name + ": " + address
            color: wrapper.ListView.isCurrentItem ? "red" : "black"
        }
    }
}

K: More attached properties (onPath?) could be discussed here. Something visual

Instructions and description for the exercise of the topic

  • How to modify the model inside the delegate
  • isCurrentItem or other attached property example

Exhaustive reference material mentioned in this topic

http://doc.qt.io/qt-5/model-view-programming.html
https://qmlbook.github.io/en/ch06/index.html#delegate
https://www.quora.com/What-are-delegates-in-Qt
https://doc.qt.io/archives/qq/qq24-delegates.html
http://doc.qt.io/qt-5/qitemdelegate.html
https://www.ics.com/designpatterns/book/delegates.html
http://doc.qt.io/archives/qt-4.8/qabstractitemdelegate.html#details
http://doc.qt.io/qt-5/qitemdelegate.html#details

Further reading topics/links:

Clone this wiki locally