Analytics

Tuesday, August 10, 2010

QML and dealing with states

In the last days I have resumed my QML work (I had a small break to work on the MGCP GW code of OpenBSC to fix some real world issues) and there is one kind of issue I tend to run in and I wonder how others are solving it. Let us imagine we have a QML Component for a Button. The Button itself can hold a text (property alias text: buttonLabel.text) and the button has three states (enabled, focused, pressed) that depend on the MouseArea that inside the button as well. Actually this approach is directly coming from the many nice examples and demos provided by Nokia.

Now the problem is... I'm using the Button in many places and depending on some other external state the label of the Button should change and I keep writing things like this:

UI.Button {
id: text_button
text: 'My Text'
MouseArea {
anchors.fill: parent
onClicked: { console.log('clicked'); }
}

states: [
State {
name: 'some-state'
PropertyChanges {
target: text_button;
text: 'Other text'; }
}
/* more states... */
]
}

And then I am going to wonder why things don't work. The first issue is that my own MouseArea will receive the mouse click and the button will not work... but that is easily fixed. Do not add a custom MouseArea and have a clicked signal inside the button component. The second issue is with the states.. the above code is breaking the focus/pressed logic.

The way I am dealing with this kind of problem is to move the state into a parent and control the text from there. What is the proper way of solving this problem? Creating multiple buttons and control the visibility/opacity from outside? Duplicate the component states inside the custom states (cross product of my states and the component states)?

I know that talking about errors is bad as this will make people remember the wrong solution but I hope that other people stepping into these kind of problems will remember this as a possible problem..

1 comment:

fleury (Eduardo M. Fleury) said...

Hi zecke,

The problem here is that at any moment, an item is in one, and only one, state.

Now imagine the following:
You use four "internal" states: pressed, enabled, focused and the default "" state.

Then, from the outside you create one or more additional states like "some_state".

Then lets assume your button was in the "enabled" state, and something happens and it goes to "some_state", that actually means it will EXIT the "enabled" state and probably unset things it had set when entered it.

The solution here is to encapsulate your internal states in an item, in the implementation of Ui.Button. For instance, move "enabled", "pressed", etc, to the namespace of the internal MouseArea, or to some other Item you might want to create.

As a rule of thumb, never create states, properties or methods in the root item of reusable components unless you want them to be public / user accessible. The idea is to keep that clean for people _using_ your component.

BR,
Eduardo Fleury