How to activate the keyboard in qml (qt) - qt

I have a Button object defined in Button.qml file, and another qml file Page.qml uses the Button object defined in Button.qml. How do I activate the keyboard input so that I can use keyboard to navigate the buttons in Page.qml. for example enter key, space key and etc.
I've tried using "focus: true", "Keys.onPressed:{}" and "onVisibleChanged: if (visible) sendBbkButton.forceActiveFocus()" both in Button.qml and Page.qml. But it does not activate the focus and keyboard for the two buttons in Page.qml.
Thanks!
Page.qml:
Rectangle {
id: bp
// some code
Button {
id: aButton
text: qsTr("Abort test1")
tooltipText: qsTr("test1")
onClicked: {
// some coding
}
anchors { right: parent.left; bottom: parent.bottom; margins: 10 }
height: contentHeight + 20
width: contentWidth + 40
}
Button {
id: bButton
text: qsTr("Abort test2")
tooltipText: qsTr("test2")
onClicked: {
// some coding
}
anchors { right: aButton.left; bottom: parent.bottom; margins: 10 }
height: contentHeight + 20
width: contentWidth + 40
}
// some code
}
Button.qml:
BorderImage {
id: button
property alias text: label.text
property alias contentWidth: label.contentWidth
property alias contentHeight: label.contentHeight
property alias buttonColor: shade.color
property string tooltipText: ""
signal clicked()
source: Style.buttonBorderImage
border { left: 10; top: 15; right: 10; bottom: 10 }
Highlight { }
width: Math.max( sourceSize.width, label.contentWidth * 1.2)
Rectangle {
id: shade
anchors.fill: parent
radius: 10
}
Rectangle {
id: focusBorder
color: "transparent"
border.color: button.activeFocus ? Style.iRobotGreen : "transparent"
anchors { fill: parent; margins: -1 }
radius: 10
}
Layout.preferredWidth: Math.max( label.implicitWidth + button.border.left
+ button.border.right,
button.implicitWidth )
Text {
id: label
anchors.centerIn: parent
font: Style.refFont1.font
}
MouseArea {
id: mouse
anchors.fill: parent
enabled: true
onClicked: button.clicked()
hoverEnabled: button.tooltipText.length > 0
onEntered: {
if (button.tooltipText.length > 0)
tooltip.show(mouseX + 16, mouseY + 16)
}
onExited: {
tooltip.hide()
}
}
ToolTip {
id: tooltip
enabled: true
text: button.tooltipText
}
}

Related

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
}
}
}
}

QML 'Custom Menu' option moving upwards

I am trying to create a "menu" in QML with custom data in each option
For requirements of my application, I need to show it loading the QML file dynamically (Qt.createComponent). What I need is to show some fixed options in the bottom part, and when clicked the top one, another options appear below this top option, which keeps in the top
A simple example. I have this menu:
Option 4
Option 2
Option 1
And when clicked in Option 4, the menu changes to
Option 4
Option 3
Option 2
Option 1
So Option 4 is moved upwards and Option 3 appears.
I would like to have a 'shadow' around all my menu (I added a DropShadow component for that purpose).
I have this simple test code, where I have a main Rectangle (to be surrounded by the shadow), and 2 Rectangles inside.
Rect1 for the fixed part (Option 1, Option 2), and Rect2 for the 'movable' part (Option 3, Option 4).
Rect2 is behind Rect1 (z: -1), and located to have only Option 4 visible, above Option 2. When clicked Option 4, Rect2 is moved upwards and all options are visible.
To achieve that, I have to update Rect2 visible height, and main window position (y value), since main window height depends on this Rect2 visible height.
I have it working, but it flicks a lot since 2 variables changes ('fixed panel' is moved upwards and back).
I have also tried with a ParallelAnimation for 2 values, but no success.
Any idea to have this menu with a smooth movement?
Main.qml:
import QtQuick 2.0
Rectangle
{
id: window
property variant win: undefined;
Component.onCompleted:
{
var component = Qt.createComponent("TestMenu.qml");
win = component.createObject(window, {"x": 500, "y": 500});
win.show();
}
}
TestMenu.qml:
import QtQuick 2.0
import QtQuick.Window 2.1
import QtGraphicalEffects 1.0
Window {
id: window
flags: Qt.Tool | Qt.FramelessWindowHint
height: panel.height
color: "transparent"
property int radiusShadow: 20
property int iOptionHeight: 30
Rectangle {
id: panel
anchors { centerIn: parent}
height: menu1.height + menu2.heightVisible + 2*radiusShadow
width: window.width - 2*radiusShadow
color: "transparent"
Rectangle {
id: menu1
anchors { bottom: parent.bottom; bottomMargin: radiusShadow }
width: parent.width
height: column1.children.length * iOptionHeight
Column {
id: column1
anchors.fill: parent
Rectangle {
color: "red";
Text { text: qsTr("option 2") }
height: iOptionHeight; width: parent.width
}
Rectangle {
color: "green";
Text { text: qsTr("option 1") }
height: iOptionHeight; width: parent.width
}
}
}
Rectangle {
id: menu2
property int heightVisible: iOptionHeight
anchors { top: parent.top; topMargin: radiusShadow; left: menu1.left }
width: parent.width
height: column2.children.length * iOptionHeight
z: -1
Column {
id: column2
anchors.fill: parent
Rectangle {
id: blue
property bool bOpen: false
color: "blue";
height: iOptionHeight; width: parent.width
Text { text: qsTr("option 4") }
MouseArea {
anchors.fill: parent
onClicked: {
blue.bOpen = !blue.bOpen;
panel.showHideMenu2(blue.bOpen);
}
}
}
Rectangle {
color: "pink";
Text { text: qsTr("option 3") }
height: iOptionHeight; width: parent.width
}
}
}
function showHideMenu2(bShow)
{
if (bShow)
{
window.y -= iOptionHeight
menu2.heightVisible += iOptionHeight;
}
else
{
window.y += iOptionHeight
menu2.heightVisible -= iOptionHeight;
}
}
}
DropShadow {
id: dropShadow
visible: true
anchors.fill: panel
radius: radiusShadow
samples: 24
color: "#40000000"
source: panel
}
}
As a quick answer for your question, you can get what you want using Behavior animation for a property change.
Here, Behavior animation will be used on y (position) change of your window, and for height change of respective rectangles.
Here is the patch for your code I recommend you to apply to see smooth movement:
## -10,6 +10,9 ##
property int radiusShadow: 20
property int iOptionHeight: 30
+ property int animationDuration: 500 // ms
+
+ Behavior on y { NumberAnimation { duration: window.animationDuration } }
Rectangle {
id: panel
## -18,6 +21,7 ##
height: menu1.height + menu2.heightVisible + 2*radiusShadow
width: window.width - 2*radiusShadow
color: "transparent"
+ Behavior on height { NumberAnimation { duration: window.animationDuration } }
Rectangle {
id: menu1
## -25,6 +29,7 ##
anchors { bottom: parent.bottom; bottomMargin: radiusShadow }
width: parent.width
height: column1.children.length * iOptionHeight
+ Behavior on height { NumberAnimation { duration: window.animationDuration } }
Column {
id: column1
## -52,6 +57,8 ##
width: parent.width
height: column2.children.length * iOptionHeight
+ Behavior on height { NumberAnimation { duration: window.animationDuration } }
+
z: -1
Column {
## -64,6 +71,7 ##
color: "blue";
height: iOptionHeight; width: parent.width
Text { text: qsTr("option 4") }
+ Behavior on height { NumberAnimation { duration: window.animationDuration } }
MouseArea {
anchors.fill: parent
## -77,6 +85,7 ##
color: "pink";
Text { text: qsTr("option 3") }
height: iOptionHeight; width: parent.width
+ Behavior on height { NumberAnimation { duration: window.animationDuration } }
}
}
}
## -105,4 +114,4 ##
color: "#40000000"
source: panel
}
-}+}
I have tried with a model and a ListView (code is simpler now), but I don't know where and how insert an 'Animation' or a 'Behaviour' to achieve my target, if it is possible to do it (I have tried several options with no success...)
The expected effect is that the 1st rectangle moves up when the 2nd appears, so the bottom one keeps in its position (at bottom). But the default behaviour when I add an element to the model is that the list increased the height downwards
Maybe anyone could help...
My code:
import QtQuick 2.0
import QtQuick.Controls 1.4
Rectangle {
id: rootItem
width: 400
height: list.height
ListModel {
id: modelRects
ListElement { rectColor: "green" }
ListElement { rectColor: "orange" }
}
ListView {
id: list
height: modelRects.count * 30
model: modelRects
delegate: Rectangle {
id: delegate
height: 30
width: rootItem.width
color: rectColor
MouseArea {
anchors.fill: parent
onClicked: onRectClicked(index);
}
}
}
function onRectClicked(index)
{
if (index == 0)
{
if (modelRects.count == 2)
modelRects.insert(1, {"idRect": 2, "rectColor": "red"});
else
modelRects.remove(1, 1);
}
}
}

QML: How to reject drop action

I have one DropArea and two elements. I want DropArea reject the drop event if the DropArea already got one element be dropped, the another element not allow drop into, unless the first one move out.
DropArea {
property bool dropped: false
onDropped: {
drop.accepted = !dropped;
dropped = true;
}
onExited: dropped = false
}
But looks like drop.accepted not work,
BTW anyway to get the objects was dropped in DropArea
You should control if the item must be dropped or not in onReleased, checking the dropped property.
Full example:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
id: win
visible: true
width: 800
height: 600
title: qsTr("Hello World")
Repeater {
model: 10
Rectangle {
id: rect
width: 50
height: 50
z: mouseArea.drag.active || mouseArea.pressed ? 2 : 1
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
x: Math.random() * (win.width / 2 - 100)
y: Math.random() * (win.height - 100)
property point beginDrag
property bool caught: false
border { width:2; color: "white" }
radius: 5
Drag.active: mouseArea.drag.active
Text {
anchors.centerIn: parent
text: index
color: "white"
}
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: parent
onPressed: {
rect.beginDrag = Qt.point(rect.x, rect.y);
}
onReleased: {
if(!rect.caught || dragTarget.dropped) {
backAnimX.from = rect.x;
backAnimX.to = beginDrag.x;
backAnimY.from = rect.y;
backAnimY.to = beginDrag.y;
backAnim.start()
}
parent.Drag.drop()
console.log("MouseArea - containsDrag " + dragTarget.dropped)
}
}
ParallelAnimation {
id: backAnim
SpringAnimation { id: backAnimX; target: rect; property: "x";
duration: 500; spring: 2; damping: 0.2 }
SpringAnimation { id: backAnimY; target: rect; property: "y";
duration: 500; spring: 2; damping: 0.2 }
}
}
}
Rectangle {
anchors {
top: parent.top
right: parent.right
bottom: parent.bottom
}
width: parent.width / 2
color: "gold"
DropArea {
id: dragTarget
anchors.fill: parent
property bool dropped: false
onEntered: {
console.log("onEntered " + containsDrag)
drag.source.caught = true;
}
onExited: {
console.log("onExited " + containsDrag)
dropped = false;
}
onDropped:
{
console.log("onDropped");
dropped = true;
}
}
}
}
Use drop.accept() instead. The above can be done as follows:
property bool containsItem: false
DropArea {
id: dropArea
anchors.fill: parent
onDropped: {
if(containsItem)
drop.accept(Qt.IgnoreAction)
else
drop.accept()
containsItem = true;
}
}
Also donot use dropped property as it is already an attached property inside onDropped event handler.
Edit:
If rect is the Item to be dragged and dropped then:
Rectangle {
id: rect
width: 40; height: 40
color: "red"
Drag.active: dragArea.drag.active
Drag.hotSpot.x: 20
Drag.hotSpot.y: 20
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
onReleased: if (rect.Drag.drop() !== Qt.IgnoreAction) {
console.log("Accepted!");
} else {
console.log("Rejected!");
}
}
}

Change Text Color of the selected item in a ListView

Let me start by saying that I am pretty new to QML.
I have a ListView (with model and delegate), it works fine in my model but I would like to change the color (currently color: skin.gray) of the selected item to something else when the item is the currentIndex-item.
ListView {
id: menuBody_listview
width: parent.width
height: parent.height
currentIndex: 0
clip: true
highlight: highlighter
highlightFollowsCurrentItem: true
Behavior on opacity {
NumberAnimation { property: "opacity"; duration: 300; easing.type: Easing.InOutQuad }
}
anchors {
top: menuHeader_listview.bottom
bottom: parent.bottom
}
model: ListModel {
ListElement {
itemIconLeft: 'images/icons/menu/pause.png'
itemText: "Cancel"
itemIconRight: 'images/icons/menu/take-me-home.png'
}
ListElement {
itemIconLeft: 'images/icons/menu/pause.png'
itemText: "Mute"
itemIconRight: 'images/nill.png'
}
ListElement {
itemIconLeft: 'images/icons/menu/repeat.png'
itemText: "Repeate"
itemIconRight: 'images/nill.png'
}
}
delegate: MenuBodyItem {
width: menuBody_listview.width
anchors.horizontalCenter: parent.horizontalCenter
iconLeft: itemIconLeft
message: itemText
iconRight: itemIconRight
}
}
Following is the code for the item which is being populated, ManuBodyItem.qml.
Item {
width: 100
height: 50
property alias iconLeft: menuitem_icon_start.source
property alias message: menuitem_text.text
property alias iconRight: menuitem_icon_end.source
RowLayout {
spacing: 20
anchors.fill: parent
Image {
id: menuitem_icon_start
fillMode: Image.PreserveAspectCrop
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
}
Text {
id: menuitem_text
anchors {
left: menuitem_icon_start.right
verticalCenter: parent.verticalCenter
verticalCenterOffset: -2
leftMargin: 20
}
color: skin.gray
font {
family: "TBD"
}
}
Image {
id: menuitem_icon_end
fillMode: Image.PreserveAspectCrop
source: iconRight
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
}
}
}
Use ListView's isCurrentItem attached property:
Text {
id: menuitem_text
anchors {
left: menuitem_icon_start.right
verticalCenter: parent.verticalCenter
verticalCenterOffset: -2
leftMargin: 20
}
color: itemDelegate.ListView.isCurrentItem ? "red" : skin.gray
font {
family: "TBD"
}
}
Note that you have to give your root delegate item an ID in order to qualify the expression above:
Item {
id: itemDelegate
RowLayout {
// ...
}
// ...
}
You can see the same approach used in the example I linked to.
From your example:
color: skin.gray is used for the Text element which will change the color of the text and not it's background viz. i understood you want.
You can use a Rectangle element here which can act as a background component to set the background color.
So instead of Item root element in the delegate you can use Rectangle. So MenuBodyItem.qml will look as
Rectangle {
width: 100
height: 50
...
}
Now to set background color to the Rectangle if it is current one you can use ListView.isCurrentItem to check.
So,
Rectangle {
color: ListView.isCurrentItem ? "cyan" : "lightblue"
width: 100
height: 50
}
and now finally you will have to set the clicked item as the current one which can be done in the MouseArea of the Delegate Item
delegate: MenuBodyItem {
width: menuBody_listview.width
anchors.horizontalCenter: parent.horizontalCenter
iconLeft: itemIconLeft
message: itemText
iconRight: itemIconRight
MouseArea {
anchors.fill: parent
onClicked: menuBody_listview.currentIndex = index
}
}

Simple TextArea Element in qml

I want to create simple TextArea element in QML and I try this code. but when write in Textarea , text's fall out of border.
Are you have simple TextArea or can you help me to improve this code:
FocusScope {
id: focusScope
width: 400; height: 50
property int fontSize: focusScope.height -30
property color textColor: "black"
property string placeHolder: "Type something..."
property string inputExpression: ".*"
property bool isUserInTheMiddleOfEntringText: false
Rectangle {
width: parent.width
height: parent.height
border.color: 'steelblue'
color: focus?'red':'#AAAAAA'
border.width: 3
radius: 0
MouseArea {
anchors.fill: parent
onClicked: { focusScope.focus = true; textInput.openSoftwareInputPanel();
}
}
}
Text {
id: typeSomething
anchors.fill: parent; anchors.rightMargin: 8
verticalAlignment: Text.AlignVCenter
text: placeHolder
color: "gray"
font.italic: true
font.pointSize: fontSize
MouseArea {
anchors.fill: parent
onClicked: { focusScope.focus = true; textInput.openSoftwareInputPanel();
}
}
}
MouseArea {
anchors.fill: parent
onClicked: { focusScope.focus = true; textInput.openSoftwareInputPanel();
}
}
TextEdit {
id: textInput
anchors { right: parent.right; rightMargin: 8; left: clear.left; leftMargin: 8; verticalCenter: parent.verticalCenter }
focus: true
selectByMouse: true
font.pointSize: fontSize
wrapMode: TextEdit.WordWrap
color: textColor
}
Text {
id: clear
text: "\u2717" // 'x'//"\u2713"
color: 'steelblue'
font.pointSize: 25
opacity: 0
anchors { left: parent.left; leftMargin: 8; verticalCenter: parent.verticalCenter }
MouseArea {
anchors.fill: parent
onClicked: { textInput.text = ''; focusScope.focus = true; textInput.openSoftwareInputPanel(); }
}
}
states: State {
name: "hasText"; when: textInput.text != ''
PropertyChanges { target: typeSomething; opacity: 0 }
PropertyChanges { target: clear; opacity: 1 }
}
transitions: [
Transition {
from: ""; to: "hasText"
NumberAnimation { exclude: typeSomething; properties: "opacity" }
},
Transition {
from: "hasText"; to: ""
NumberAnimation { properties: "opacity" }
}
]
}
thank's for help
This code should do what you want :
import QtQuick 2.0
FocusScope {
id: focusScope;
width: 400;
height: textInput.paintedHeight + (2 * textInput.anchors.topMargin);
property alias value : textInput.text;
property alias fontSize : textInput.font.pointSize;
property alias textColor : textInput.color;
property alias placeHolder : typeSomething.text;
Rectangle {
id: background;
anchors.fill: parent;
color: "#AAAAAA";
radius: 5;
antialiasing: true;
border {
width: 3;
color: (focusScope.activeFocus ? "red" : "steelblue");
}
}
TextEdit {
id: textInput;
focus: true
selectByMouse: true
font.pointSize: 20;
wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere;
color: "black";
anchors {
top: parent.top;
topMargin: 10;
left: parent.left;
leftMargin: 10;
right: parent.right;
rightMargin: 10;
}
}
Text {
id: typeSomething;
text: "Type something...";
color: "gray";
opacity: (value === "" ? 1.0 : 0.0);
font {
italic: true
pointSize: fontSize;
}
anchors {
left: parent.left;
right: parent.right;
leftMargin: 10;
rightMargin: 10;
verticalCenter: parent.verticalCenter;
}
Behavior on opacity { NumberAnimation { duration: 250; } }
}
MouseArea {
visible: (!focusScope.activeFocus);
anchors.fill: parent
onClicked: { textInput.forceActiveFocus(); }
}
Text {
id: clear;
text: "\u2717" // 'x' //"\u2713"
color: 'steelblue';
font.pixelSize: 30;
opacity: (value !== "" ? 1.0 : 0.0);
anchors {
right: parent.right;
bottom: parent.bottom;
margins: 5;
}
Behavior on opacity { NumberAnimation { duration: 250; } }
MouseArea {
anchors.fill: parent
onClicked: {
value = "";
focusScope.focus = false;
}
}
}
}
I also fixed many things in you code, like multiple MouseArea for the same use, binding loops, bad anchors/alignements, etc...

Resources