Qt QML Hot Tips #6

Qt QML Hot Tips #6

Part 6 - The "Unbinding"

Like sounding like a potential horror film title, this article is inspired by a shuddering comment I heard yesterday during a meeting:

"I added an API to make it unbindable..."

My first reaction was to mentally vomit and immediately sketch this parody:

QtObject {
   someProperty !: someOtherProperty // unbinding operator !:
}        

I shall not go into the detail of what the developer was even trying to do and why, as that is a whole other heartache... but it did make me stop and think of all the ways that an "unbinding" actually already exists - and may have valid use cases (unlike the aforementioned).

And so for the sheer fun of it I thought I'd write a rather unconventional list of the ways of how not to do bindings.

Hottest Tip!

Stop right now and do yourself a favour and turn on the Logging Category for the detection of Binding Removal! Put it in your global logging category configuration right now!


QT_LOGGING_RULES="qt.qml.binding.removal.info=true"

// credit: contributed by KDAB, Qt 5.10        

See the following for more details:

This will print out a really nice message telling what you did wrong and where. If you see this, you will have just found the source of your ugly problem and is the key to telling you that you probably need to think about your QML architecture.

( Qt公司 may consider trying this out on their own code - since there's a few knocking around.)

Can I break it "properly"?

Yes, you can. But before I begin, I have never encountered a single occasion when breaking a binding was actually intended by the developer!

Classic Mistake


Item {
   width: 100
   height: width // binding
   Component.onCompleted: height = 200 // assignment
}        

Obviously this is contrived and it is easy to see how the height property binding here is being removed by the assignment. But there are much more complex cases where this isn't immediately so clear if the assignment is applied through some other obscure means, perhaps even outside the current context. There are some cases where this happens deliberately (see below) but generally these are incredibly difficult to find and you only notice when you UI starts subtly playing up. That's where the logging category is your absolute life saver. Go back up and set it, because I'll bet you didn't. If your code is good, you can set it and forget it.

C++ Signals and Slots

Whenever you use QObject::connect with any of its overloads you implicitly create a relationship between the source and the target objects concerning their lifetime and the "binding" created here will cease to exist once either of the two objects is deleted.

Unbinding: using QObject::disconnect or any of its related functions. There are of very valid reasons for doing this, so this isn't on next year's naughty/nice list.

C++ QProperty

A relative newcomer to the party is the powerful C++ QProperty class. This, if you hadn't read the extensive postings about it, is a way to create QML-style bindings in C++ on your QObjects making exquisite yet easy to read property binding expressions possible.

Unbinding: QProperty::takeBinding will remove the binding. Also QProperty::setValue will assign the new value and remove any exiting binding.

QML Connections


Connections {
? ? target: mouseArea
? ? function onClicked(mouse) { foo(mouse) }
    enabled: false // does not respond to onClicked
}        

Unbinding: set (or bind) enabled to false! Note that enabled is itself is a property which can be bound. This is a trick really because the binding is actually still there but is effectively blocked.

QML Binding


Binding on value {
? ? when: mouseArea.pressed
? ? value: mouseArea.mouseX 
    // value is updated whenever mouseX changes while pressed
}        

Unbinding: set (or bind) the when property to false.

Note that the behaviour of what happens to value when "when" goes false has changed between Qt versions and you should take care of what is called the restoreMode and its current default behaviour.

JavaScript Disconnect

This one is maybe a bit rare, but worth a mention (note that the traditional on "onSignalName" format is not used here, you actually disconnect on the signal name directly:


QtObject 
? ? id: helperObject
    
    function clickHandler () { /.../ }

? ? function remove() {
? ? ? ? mouseArea.clicked.disconnect(customClickHandler)
? ? }
}        

Unbinding: In so disconnecting the signal handler, it acts exactly like QObject::disconnect.

QML PropertyChanges

Part of the QML State system provided on all [QQuick]Item derivatives, PropertyChanges makes it possible to create variants of a given object based on its QString state property. This is is the supporting mechanism leveraged by Qt Design Studio and the relatively new Figma Variants as generated by the Qt Figma Bridge metadata import (Enterprise licence holders only - sorry folks! Take that up with Qt公司 who made that odd decision...)

Unbinding: I'll not paste an example here since the docs cover it well enough but suffice to say that PropertyChanges can and will change and potentially remove bindings by replacing existing bindings with other bindings or values or even undefined values. These may or may not be intentional and may not show up in the qt.qml.binding.removal logging category output, and things can easily get complicated if you have multiple places in your QML that may wish to modify the properties listed in PropertyChanges. All I can say here is be very careful!

Rule of thumb: if a property is controlled by a state, then it has exclusive rights to do that - else things go wrong.

Please note carefully the behaviour of the restoreEntryValues property as to how "permanent" the changes are.

Other Gotcha Unbindings

There are so many other places where "Unbinding" can occur so with the caveat of there probably being loads of other ways ranging from the contrived to the exotic, here's one more example where you can also do your worst work - Animations. These include all the usual suspects and notably PropertyAction and ScriptAction which are usually found inside a Transition structure as part of an Item state system.

Unbinding: All of the Animation derivatives have the capability of writing property values onto your object property which may have a binding. ScriptAction is particularly nasty in that you can do anything with it.

Rule of thumb: if a property is controlled by an animation, then it may have exclusive rights to do that - since animations may not always be running. In the case of an animation being part of a Transition, then exclusivity is a somewhat given.

Conclusion

So after the initial sarcasm and horror, there actually is such a thing as an "unbinding" and there are several reasons and methods to be quite intentional about it. In those cases, be absolutely intentional - and be careful of "who is primarily responsible" for the property's changes.

And turn on the binding removal logging category to tell you when you aren't.

Cyril Lorquet

A human-first, highly communicative and efficient software engineer. I deliver qualitative solutions to today’s world challenges through ambitious and innovative projects and software products.

2 年

Very good read, I definitely recommend it - unintended ??unbindings?? can be tough to spot and a nightmare to debug especially on an existing codebase. Thanks !

要查看或添加评论,请登录

Mike Trahearn的更多文章

  • Qt QML Hot Tips #9

    Qt QML Hot Tips #9

    Part 9 - Move your QML over to the DARK side..

    11 条评论
  • #QtStories - My Experience. My Story. Your Future!

    #QtStories - My Experience. My Story. Your Future!

    The letters 'Q' and 't' have been at the core of my career and I would like to take a couple of moments to explain why.…

    6 条评论
  • Qt QML Hot Tips #8

    Qt QML Hot Tips #8

    Part 8 - How to save face by using namespaces - a quick guide to QML and enums! Following a rather extended period…

  • Qt QML Hot Tips #7

    Qt QML Hot Tips #7

    Part 7 - Does my RCC look BIG in this? Or, "How to handle your large assets"..

    1 条评论
  • Qt QML Festive Hot Tips

    Qt QML Festive Hot Tips

    Ho Ho Hot Tips - Christmas Special! While your projects are getting stuffed and your turkey is still compiling I…

  • Qt QML Hot Tips #5

    Qt QML Hot Tips #5

    Part 5 - I'm sorry, your access is restricted! From Qt 5.15 and much more strictly in Qt 6, a series of improvements…

  • Qt QML Hot Tips #4

    Qt QML Hot Tips #4

    Part 4 - May I See Your ID? In this article I cover one of the easiest parts of the QML syntax - but its inclusion in…

    3 条评论
  • Qt QML Hot Tips #3

    Qt QML Hot Tips #3

    Part 3 - Are your properties required? if(someObjectProperty !== null) someObjectProperty.callFunction() is found…

    6 条评论
  • Qt QML Hot Tips #2

    Qt QML Hot Tips #2

    Welcome to Part 2! Continuing on a theme of raging against the tide of poorly written QML using examples from years of…

  • Qt QML Hot Tips #1

    Qt QML Hot Tips #1

    Welcome! This is the first of many extremely short articles containing some absolute nuggets of gold stashed away until…

    12 条评论