PDA

View Full Version : How to manage Focus with States in my custom QML component?



Dharkael
2nd September 2016, 23:42
I´ve created a draggable custom Component in order to manage the geometry of individual Quick Controls Components.

The componet has 2 parts:


The "Manipulator" which is a draggable and resizable Rectangle
The inner component which is in the center of the manipulator


Description of the behavior:


No focus: the default state, the Manipulator is invisible and you can only see the inner component

Focused: When you click the component (or try to drag it) you enter this state and the Manipulator becomes visible but you can´t access the inner component. Disabled pressing Escape or clicking outside the component (goes to state 1)

Inner Focus: when you double click on the component The Manipulator keeps visible and you can still still resize but the the inner component has the main focus (for example a TextEdit now could be editable). Disabled pessing Escape (goes to state 2) or clicking outside the component (goes to state 1)


Example of the Component when the Manipulator area is visible:
http://i.stack.imgur.com/94eOk.png

The logic of this component would be similar to the logic of a folder in a Desktop Enviroment (except for resizing) The manipulator would be the folder itself and the inner component is its name.

analogy with folder:
http://i.stack.imgur.com/sLmaf.png

Here I post a simplified version of my manipulator, I´m sure it will help to construct an answer, (I tried a lot of variations for several hours, this is one of those not functional attempts)


FocusScope{
id: root
width: 175; height: 25;
focus: true

states: [
State {
name: "noFocus"
when: !manipulator.activeFocus && !innerComp.activeFocus
PropertyChanges {
target: innerComp
enabled: false
}
PropertyChanges {
target: manipulator
visible: false
}
},

State {
name: "focused"
when: manipulator.activeFocus
PropertyChanges {
target: innerComp
enabled: false
}
PropertyChanges {
target: manipulator
visible: true
}
},
State {
name: "innerFocus"
when: innerComp.activeFocus
PropertyChanges {
target: innerComp
enabled: true
}
PropertyChanges {
target: manipulator
visible: true
}
}
]

//visual area of manipulation (drag, redimension, etc)
MouseArea{
id: manipulator
anchors.fill: parent

onDoubleClicked: forceActiveFocus(innerComp) //go to state 3 "innerFocus"
drag.target: manipulator

Keys.onEscapePressed: forceActiveFocus(root) //I don´t think this is the correct to loose focus but I don´t know how to do that

Rectangle {
id: background
anchors.fill: parent
color: "lightsteelblue";
}
}
//Inner Component (TextField for example)
InnerComp {
id: innerComp
anchors.fill: parent

Keys.onEscapePressed: forceActiveFocus(manipulator) //return state 2 "focused"
}
}

I posted my question in StackOverflow: http://stackoverflow.com/questions/39298647/ but I thought this would be a good place to ask too.

anda_skoa
3rd September 2016, 16:20
Mybe reverse the dependency, i.e. make the focus depend on the state, not the state depend on the focus?

So events like click, double, escape, change the state and the state changes focus if necessary.

Cheers,
_

Dharkael
3rd September 2016, 22:23
Mybe reverse the dependency, i.e. make the focus depend on the state, not the state depend on the focus?

So events like click, double, escape, change the state and the state changes focus if necessary.

Cheers,
_

Thank you for this advice, I adapted the example as you sugested and now it works!
I post the code here for those who could be interested in a solution (as I said this is a simplified version of the real code):


Item {
id: root
width: 175; height: 25;

states: [
State {
name: "noFocus"

PropertyChanges {
target: innerComp; enabled: false
}
PropertyChanges {
target: background; visible: false
}
PropertyChanges {
target: manipulator; focus: true
}
},

State {
name: "focused"

PropertyChanges {
target: innerComp; enabled: false
}
PropertyChanges {
target: background; visible: true
}
PropertyChanges {
target: manipulator; focus: true
}
},
State {
name: "innerFocus"

PropertyChanges {
target: innerComp; enabled: true
}
PropertyChanges {
target: background; visible: true
}
PropertyChanges {
target: manipulator; focus: true
}
}
]
state: "noFocus"

//visual area of manipulation (drag, redimension, etc)
MouseArea{
id: manipulator
anchors.fill: parent

onPressed: {
root.state = "focused"
forceActiveFocus(manipulator) //this prevents loosing focus in some especific situations
}
onDoubleClicked: {
root.state = "innerFocus"
forceActiveFocus(manipulator) //this prevents loosing focus in some especific situations
}
Keys.onEscapePressed: root.state = "noFocus"

}
Rectangle {
id: background
anchors.fill: parent
color: "lightsteelblue";
}
//Inner Component (TextField for example)
InnerComp {
id: innerComp
anchors.fill: parent

Keys.onEscapePressed: root.state = "focused"
}
}

anda_skoa
4th September 2016, 09:44
In case you want to move the "forceActiveFocus" also into the state, then you can do so using http://doc.qt.io/qt-5/qml-qtquick-statechangescript.html

Cheers,
_