QML tips: use required property in delegate instead of relying on the model variable

So instead of doing this:

ListView {
    model: MyModel {}
    delegate: QQC2.ItemDelegate {
          contentItem: QQC2.Label {
              text: model.title
          }
    }
}

Do this:

ListView {
    model: MyModel {}
    delegate: QQC2.ItemDelegate {
          id: myDelegate

          required property string title
          
          contentItem: QQC2.Label {
              text: myDelegate.title
          }
    }
}

This has the following advantages:

  • This code will be easier to compile with the new qt6 qml compilers
  • This makes it easier to move the delegate to it’s own component without having to rely on a magic model variable
  • Makes it also easier to test the delegate alone in a QML Unit test

Qmllint from qt6 will warm you about usage of the model variable and recommand you to use required properties instead.

5 Likes

This code will be easier to compile with the new qt6 qml compilers

how’s so? I mean, what makes it easier, and how is it noticeable for developers?

This makes it easier to move the delegate to it’s own component without having to rely on a magic model variable

While I like the idea behind required properties, refactoring them out is actually where they can hurt the most.

Imagine, you had a QML supertype for your delegate, say BaseButton, without required properties at all, just a regular component. You use it as a delegate in some view like this: delegate: BaseButton { test: model.text }. Now, if you were to mark some of its properties as required (or add a new, required one), your code would stop working without manual adjustments in every place where you instantiated that BaseButton. That’s because when a view-model detects that a delegate has at least one required property, it would (pretty suddenly, especially for newcomers) stop injecting that magical model object into context. In fact, you’d event lose ability to fetch additional roles, e.g. if their names clash with existing properties, or you’d lose access to delegate’s model index if you happened to have a role whose name is mapped to index.

So, that’s actually quite controversial. I’d really wish Qt guys came up with something more generic and explicitly controllable rather than stacking black magic on top of more black magic :thinking:

Also, pro tip:

This is a valid syntax to redeclare an existing property as required. It surely kinda breaks substitution principle of inheritance a little bit. But is a yet another way to mess around with model-delegates.

QQC2.ItemDelegate {
      id: myDelegate
      required text
}

See QML/syntax_test_QML.qml at 24d8601f1dfbe13df81ce36f4624c1acd609b341 · SublimeText/QML · GitHub

See New QML language features in Qt 5.15 (quote: This avoids unqualified lookups, which are problematic for tooling, and tend to be slower.) and Compiling QML to C++: Fixing unqualified access (quote: Without the required property it takes 804µs in total, of which 718µs are spend on executing the JavaScript. With the required property we get 654µs and 596µs.)