Qt QML Hot Tips #3
Mike Trahearn
Qt Champion??????, Qt QML C++ Specialist, Director, Codecept Software Pty Ltd; A Unique Thinker, Detailed Craftsman with Precise Foresight and a Personal Approach
Part 3 - Are your properties required?
if(someObjectProperty !== null) someObjectProperty.callFunction() is found littered throughout QML there are more things we could do to make that statement a bit nicer using nullish coalescing (Qt 5.15) and optional chaining (Qt 6.0). But we still encounter the fundamental problem: we kind of really expect someObjectProperty to be something really and the null case is really not nice but since our 10% code 90% error handler mindset is entrenched, there it is and people got used to it.
So be something!
From Qt 5.15 onwards we now have a nice shiny new keyword we can decorate our properties with: required
You can add required properties to your own components e.g.
// MyType.qml
Control {
// the value property must be set if MyType is declared anywhere
required property int value
}
// usage elsewhere:
MyType {
// if not set with binding or assignment, an error is generated
value: 10
}
Or you can make an existing property on an existing type required e.g.
// MyText.qml
Text {
// make the existing property text "required"
required property text
}
// usage elsewhere:
MyText {
text: "must be set" // else error!
}
Note: You can't assign an initial value to a required property from QML, as that would go directly against the intended usage of required properties. Note also that readonly required properties are also counter productive for what should be obvious reasons.
Your presence is required...
A "required" property will produce a compile time error if a delegate (or any QML component) does not elsewhere explicitly initialise or bind to it.
Consider this like a compiler complaining you did not pass in the required additional parameters for a re-implemented c++ constructor - the same can now go for QML and is part of the concept of treating your QML as a proper "class" - which is coming soon to a type compiler near you...
Use Required Properties:
Using required properties allows the component to be moved into new contexts or parent without fear of only knowing if it will work at run-time as the compiler will tell you if the new context or parent doesn't set those properties. You've never moved a QML file right and it just worked? Yeah. I thought so. This way will at least (helpfully) tell you your effort to refactor was woefully inadequate and you need to think about it a bit more carefully.
I'm trying really hard not to get into object ids right now as I'll be writing about that another time, but yes, they are very important and there are seldom (but notable) times when not to set one.
There's a bit more info in the following blog post and documentation.
Solutions Engineer at The Qt Company
1 年There's a small detail when using required properties on QML elements that is easily overlooked. If you use the required keyword when creating a delegate with default attached model roles, such as ListView with index or modelData, these roles will fail to be found at runtime. From the Models and Views in Qt Quick documentation: If a delegate contains required properties, the named roles are not provided. Instead, the QML engine will check if the name of a required property matches that of a model role. If so, that property will be bound to the corresponding value from the model. https://doc.qt.io/qt-6/qtquick-modelviewsdata-modelview.html#models Example: //main.qml ListView { model: [1, 2, 3] delegate: MyText { value: modelData } } //MyText.qml Text { text: value property int value } Adding the "required" keyword to the value property will cause the delegate to fail creation. The solution is to explicitly create properties for the named roles. //MyText.qml Text { text: value required property int value required property int modelData } Hope this helps anyone who ran into this issue!