Focusable Qml Components (Focus My Control On Tab) - qt

i have created a custom button in qml, which i want to focus on pressing 'tab', i mean "jump to it on pressing tab if its on top of queue" by default qml has this functionality on button itself and some of other controls too but what about new components which does not exist,i saw a "FocusScope" control of qml but there is no documentation of using it and i am not sure how can i implement it, here is my control :
import QtQuick 2.4
Item {
id: button
width: innerText.width + 10
height: 30
property alias text: innerText.text;
property alias font: innerText.font;
property color color: "#00171f"
property color hoverColor: "#00395f"
property color pressColor: "#3E65FF"
property int fontSize: 12
property int borderWidth: 0
property int borderRadius: 2
property bool highlighted : true
onEnabledChanged: state = ""
signal clicked
property var background
Rectangle {
id: rectangleButton
anchors.fill: button
radius: borderRadius
color: button.enabled ? button.color : "grey"
border.width: borderWidth
border.color: "black"
Text {
id: innerText
font.pointSize: fontSize
font.family: "B Nazanin"
color: "white"
anchors.centerIn: rectangleButton
}
}
//change the color of the button in differen button states
states: [
State {
name: "Hovering"
PropertyChanges {
target: rectangleButton
color: hoverColor
}
},
State {
name: "Pressed"
PropertyChanges {
target: rectangleButton
color: pressColor
}
}
]
//define transmission for the states
transitions: [
Transition {
from: ""; to: "Hovering"
ColorAnimation { duration: 200 }
},
Transition {
from: "*"; to: "Pressed"
ColorAnimation { duration: 10 }
},
Transition {
from: "*"
to: ""
ColorAnimation { duration: 200 }
}
]
//Mouse area to react on click events
MouseArea {
hoverEnabled: true
anchors.fill: button
onEntered: { button.state='Hovering'}
onExited: { button.state=''}
onClicked: { button.clicked();}
onPressed: { button.state="Pressed" }
onReleased: {
if (containsMouse)
button.state="Hovering";
else
button.state="";
}
}
}

It looks like you are simply looking for the activeFocusOnTab property:
Item {
id: button
activeFocusOnTab: true
// ...
}

Related

Qt-Quick button radius issue

I'm having an issue with a Qt Quick custom button. The planned behaviour is the button background, border, and text changes color on hover and pressed actions. The color change aspect is working, but when the button is pressed, it appears to lose it's radius setting (image of button states). I thought this might be related to the highlighted setting, but setting that to false, doesn't fix it. Any ideas what might be causing this behaviour?
import QtQuick 2.15
import QtQuick.Controls 2.15
Button {
id: customButton
text: qsTr("Custom Button")
highlighted: false
flat: true
implicitWidth: 200
implicitHeight: 40
// Custom Properties
// Button Colors
property color defaultButtonColor: "#DB8000"
property color hoverButtonColor: "#784491"
property color pressedButtonColor: "#315718"
// Text Colors
property color defaultTextColor: "#ffffff"
property color hoverTextColor: "#ffffff"
property color pressedTextColor: "#000000"
QtObject {
id: internal
property var dynamicColor: if (customButton.down) {
customButton.down ? pressedButtonColor : defaultButtonColor
} else {
customButton.hovered ? hoverButtonColor : defaultButtonColor
}
property var dynamicText: if (customButton.down) {
customButton.down ? pressedTextColor : defaultTextColor
} else {
customButton.hovered ? hoverTextColor : defaultTextColor
}
}
background: Rectangle {
id:bg_customButton
radius: 15
color: internal.dynamicColor
border.color: "#000000"
}
contentItem: Item {
id: item1_customButton
Text {
id: text_customButton
text: customButton.text
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: internal.dynamicText
}
}
}
Edit: Don't think it's the radius changing, something is being displayed over the baackground during the pressed event as the border is partial visible if more contrasting colors are used pressed button edges
Edit#2: Same behaviour when trying to use States, as suggested by #TOHO, but there could be errors in this given it's a first attempt as using them.
import QtQuick 2.15
import QtQuick.Controls 2.15
Button {
id: customButton
// Button Colors
property color defaultButtonColor: "#DB8000"
property color hoverButtonColor: "#784491"
property color pressedButtonColor: "#315718"
// Border Colors
property color defaultBorderColor: "#ffffff"
property color hoverBorderColor: "#ffffff"
property color pressedBorderColor: "#FF0800"
// Text Colors
property color defaultTextColor: "#ffffff"
property color hoverTextColor: "#ffffff"
property color pressedTextColor: "#000000"
text: qsTr("Custom Button")
clip: false
highlighted: false
flat: true
hoverEnabled: true
implicitWidth: 200
implicitHeight: 40
onHoveredChanged: if (hovered) {bg_customButton.state = "HOVER"} else {bg_customButton.state = "DEFAULT"}
onReleased: bg_customButton.state = "DEFAULT"
onPressed: bg_customButton.state = "PRESS"
background: Rectangle {
id: bg_customButton
radius: 15
border.color: defaultBorderColor
state: "DEFAULT"
states: [
State {
name: "DEFAULT"
PropertyChanges { target: bg_customButton; color: defaultButtonColor; border.color: defaultBorderColor}
PropertyChanges { target: text_customButton; color: defaultTextColor}
},
State {
name: "HOVER"
PropertyChanges { target: bg_customButton; color: hoverButtonColor; border.color: hoverBorderColor}
PropertyChanges { target: text_customButton; color: hoverTextColor}
},
State {
name: "PRESS"
PropertyChanges { target: bg_customButton; color: pressedButtonColor; border.color: pressedBorderColor}
PropertyChanges { target: text_customButton; color: pressedTextColor}
}
]
}
contentItem: Item {
id: item1_customButton
clip: true
Text {
id: text_customButton
text: customButton.text
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
state: "DEFAULT"
}
}
}
your problem was that hoverEnabled was false (by default),
and as I said in comments this is not best practice but here is a working example:
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
id: root
anchors.fill: parent;
color: "grey"
Button {
anchors.centerIn: parent;
id: customButton
text: qsTr("Custom Button")
highlighted: false
flat: true
implicitWidth: 200
implicitHeight: 40
hoverEnabled: true
// Custom Properties
// Button Colors
property color defaultButtonColor: "#DB8000"
property color hoverButtonColor: "#784491"
property color pressedButtonColor: "#315718"
// Text Colors
property color defaultTextColor: "#ffffff"
property color hoverTextColor: "#ffffff"
property color pressedTextColor: "#000000"
readonly property color currentColor: down? pressedButtonColor: hovered ? hoverButtonColor : defaultButtonColor;
readonly property color currentTextColor: down? pressedTextColor: hovered ? hoverTextColor : defaultTextColor;
background: Rectangle {
id:bg_customButton
radius: 15
color: customButton.currentColor
border.color: "#000000"
}
contentItem: Item {
id: item1_customButton
Text {
id: text_customButton
text: customButton.text
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: customButton.currentTextColor
}
}
}
}

How to animate adding and removing element to Layout in QML?

I want to animate adding and removing of TextField in ColumnLayout. Basically I want to animate like this:- https://doc.qt.io/qt-5/videos/viewtransitions-basic.mp4
As a ColumnLayout uses the implicitHeight to position the items, you can add an animation to that to create the sliding effect. I used a wrapping Item to preserve the implicitHeight of the TextField itself. It may not look perfect, but I don't think you cannot get that much further
Item {
visible: your_property_here
implicitHeight: visible ? text.implicitHeight : 0
Behavior on implicitHeight { NumberAnimation { duration: 500 } }
TextField {
id: text
anchors.fill: parent
scale: parent.visible ? 1 : 0.2
Behavior on scale { NumberAnimation { duration: 500 } }
}
}
I didn't found effective answer. Until then I'm using column as workaround
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
Page {
id: page_root
component ETextField : TextField {
width: root.width/2
}
state: "LOGIN"
Column {
anchors.centerIn: parent
ETextField {
id:host
placeholderText: "Host e.g:- exam.server.com:8080"
}
ETextField {
id:uane
placeholderText: "Username"
}
ETextField {
id: passwd
placeholderText: "Password"
}
ETextField {
id: confirm_passwd
placeholderText: "Confirm Password"
}
RowLayout {
Button {
id: submit
text: "Login"
}
Button {
id: change_state
text: "Register Instead"
onClicked: page_root.state = page_root.state === "LOGIN" ? "REGISTER" : "LOGIN"
}
}
}
states: [
State {
name: "LOGIN"
PropertyChanges {
target: confirm_passwd
height: passwd.height
}
PropertyChanges {
target: change_state
text : "Register Instead"
}
},
State {
name: "REGISTER"
PropertyChanges {
target: confirm_passwd
height: 0
}
PropertyChanges {
target: change_state
text : "Login Instead"
}
}
]
transitions: [
Transition {
from: "LOGIN"
to: "REGISTER"
NumberAnimation {
target: confirm_passwd
property : "height"
duration: 100
}
},
Transition {
from: "REGISTER"
to: "LOGIN"
NumberAnimation {
target: confirm_passwd
property : "height"
duration: 100
}
}
]
}

Is there a way in QML to change a buttons color on multiple events?

I am new to Qml and I am a little bit lost. I want to set multiple states for an Image, or a color of a button. One simpler part is, that if the button is pressed, it should change color or image. This can be achieved by the following:
Button {
width: 50
height: 50
background: Rectangle {
color: parent.pressed ? "red" : "blue"
}
}
In Addtion I have also the states: clicked, enabled, enabled clicked and many more.
So first: Can I do just catch the parent.pressed without an else statement, something like:
if (parent.pressed)
color = "red"
elseif (onClicked)
color = "blue"
....
and maybe setting additional states, which I can ask for and change my color, when my backend is disabling or enabling any of my GUI elements.
So basically I have two problems: how to catch a event in an if statement and how to catch multiple events and not using that if else statement like:
parent.pressed ? "red" : "blue"
I got further, it is possible to add states.
Button {
width: 50
height: 50
id: btn
onClicked: state="clicked"
onPressed: state="pressed"
background: Rectangle
{
anchors.fill: parent
}
states: [
State {
name: "clicked"
PropertyChanges { target: btn; background: color= "red" }
},
State {
name: "pressed"
PropertyChanges { target: btn; background: color= "blue" }
}
]
}
But this won't change the color of my button, but the rest of the UI.
I guess you have syntax error in your code.
Actually it should be something like the following:
Button {
id: btn
text: "Click me"
property color bgColor
anchors.centerIn: parent
state: pressed ? "pressed" : "regular"
background: Rectangle {
color: btn.bgColor
}
states: [
State {
name: "regular"
PropertyChanges {
target: btn
bgColor: "orange"
}
},
State {
name: "pressed"
PropertyChanges {
target: btn
bgColor: "green"
}
}
]
}
or you can play with the Rectangle:
background: Rectangle {
id: bg
}
states: [
State {
name: "regular"
PropertyChanges {
target: bg
color: "orange"
}
},
State {
name: "pressed"
PropertyChanges {
target: bg
color: "green"
}
}
]

auto KeyNavigation.tab for custom components "rectangle or item" in QML

in Qml there is auto key navigation for already known components like checkbox,textfield,button and etc , i have my custom component which is a item or rectangle and i want same functionality for it,without writing
KeyNavigation.tab: componentid
here is one of my custom controls :
Rectangle {
signal clicked
property alias font : icoText.font.family
property alias icon : icoText.text
property alias size : icoText.font.pixelSize
property alias toolTip : tooltipText.text
property string colorEnter :"#0481ff"
property string colorExit :"#00171f"
id: root
implicitWidth: 50
implicitHeight: 50
//width: childrenRect.width
radius: 0
//height: childrenRect.height
color: colorExit
state: "default"
Text {
id: icoText
text: ""
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 25
font.family: "fontawesome"
visible: text!= ""
color: "white"
}
ToolTip {
id:tooltipText
text: ""
delay: 500
timeout: 2000
visible: mouseArea.containsMouse && text!=""
font.family: "B Nazanin"
contentItem: Text {
text: tooltipText.text
font: tooltipText.font
color: "white"
}
background: Rectangle {
color: "#cc000000"
border.color: "black"
}
}
InnerShadow {
id:shadow
anchors.fill: icoText
radius: 1.0
samples: 17
horizontalOffset: 1
color: colorExit
source: icoText
visible: false
}
MouseArea{
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: root.color = colorEnter
onExited: root.color = root.state == "transparent"? "transparent" : root.colorExit
onPressed: {
shadow.visible = true
}
onReleased: {
shadow.visible = false
}
onClicked: {
root.clicked()
}
}
states: [
State {
name: "transparent"
PropertyChanges {
target: root
color:"transparent"
}
PropertyChanges {
target: icoText
color:colorExit
}
},
State{
name: "default"
PropertyChanges {
target: root
color:colorExit
}
PropertyChanges {
target: icoText
color:"white"
}
}
]
}
which will be inside a page like this :
Item{
myControl{
}
myControl{
}
}
this component by default does not loop through pressing tab what should i do?
i already tried this without success, i think this should be inside FocusScope but cause of poor documentation i did not get a simple example for this
set activeFocusOnTab on parent and focus:true in child you want to get focus
Rectangle{
activeFocusOnTab: true
Control{
focus: true
}
}
Focusable Qml Components (Focus My Control On Tab)
For my experience key navigation only works with native components like checkbox, textfield, button, etc.
To work arround this problem I used a fake native component hided with the same size of my custom component like the next example:
Rectangle {
id: myCustomComponent1
width: 100
height: 100
color: red
Button {
id: buttonFake1
text: "My Accessible text Component 1"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake2
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake1.focus = true
}
}
}
}
Rectangle {
id: myCustomComponent2
width: 100
height: 100
color: green
Button {
id: buttonFake2
text: "My Accessible text Component 2"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake1
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake2.focus = true
}
}
}
}

Custom Button inheritance (like in OOP rules)

I have made custom Button in QML and I want it to be the base item for all buttons in my project. What I want is to derive (like in OOP) buttons from it to change functionality. At first, every derived button should have its own onClicked response.
Is this possible in QML and if it is, how?
It's possible.
Here is an example of my BaseButton type. When BaseButton is clicked it emits a custom signal, in my code it's sgnClicked.
BaseButton.qml
import QtQuick 2.0
Item {
id:idButton
signal sgnClicked()
signal sgnClickMaintained()
signal sgnEntered()
signal sgnExited()
signal sgnReleased()
signal sgnPressed()
signal sgnCanceled()
property alias label: idText
property alias text: idText.text
property string iconSourceUp:""
property string iconSourceDown:""
property string iconSourceDisabled:""
property alias backgroundWidth: background.width
property alias backgroundHeight: background.height
property alias backgroundRect: backgroundRect
property alias hover: touchArea.enabled
width: 100
height: 20
Text{
id:idText
//text: "Button"
color:"white"
anchors.centerIn: parent
font.pointSize: 12
}
//if maintained at each 300 ms resend signal
Timer{
id:timer
running: false
repeat: true
interval: 300
onTriggered: sgnClickMaintained()
}
Image{
id:background
z: -1
width: parent.width
height: parent.height
source:iconSourceUp
visible: source.toString() !== ""
}
Gradient {
id:idGradient
GradientStop { position: 0 ; color: touchArea.pressed ? "#ccc" : "#eee" }
GradientStop { position: 1 ; color: touchArea.pressed ? "#aaa" : "#ccc" }
}
Rectangle {
id: backgroundRect
width: parent.width
height: parent.height
border.color: "#888"
color: enabled ?"":"lightgrey"
radius: 4
z: -1
visible: !background.visible
gradient: enabled ?idGradient:null
}
MouseArea{
id: touchArea
anchors.fill: parent
hoverEnabled: true
onCanceled: idButton.sgnCanceled()
onClicked:
{
idButton.sgnClicked()
}
onEntered: idButton.sgnEntered()
onExited: idButton.sgnExited()
onPressAndHold: {
timer.restart()
idButton.sgnClickMaintained()
}
onReleased:{
idButton.state = "up"
timer.stop()
idButton.sgnReleased()
}
onPressed:
{
idButton.state = "down"
idButton.sgnPressed()
}
}
onEnabledChanged: {
if(enabled === false)
{
idButton.state = "disabled"
timer.stop()
}
else{
idButton.state = "up"
}
}
states: [
State {
name: "down"
PropertyChanges {
target: background
source: iconSourceDown
}
},
State {
name: "disabled"
PropertyChanges {
target: background
source: iconSourceDisabled
}
},
State {
name: "up"
PropertyChanges {
target: background
source: iconSourceUp
}
}
]
Component.onCompleted:{
if(enabled)
{
state = "up"
}
else
{
state = "disabled"
}
}
}
To make a new Button inheriting from BaseButton you should instantiante the BaseButton as root item and in the slot onSgnClicked write what you want your button should do when clicked.
CustomButton.qml
import QtQuick 2.0
BaseButton {
width: 100
height: 50
onSgnClicked: {
//do something
}
}

Resources