Prevent QML MouseArea from taking focus when pressed - qml

In my application, I have a TextArea, and under it a toolbar with Button items. Whenever a Button gets pressed, the TextArea loses focus, and hides the virtual keyboard (which is right). But what if I want the TextArea to keep its focus, even if a Button has been pressed?
In SailfishOS, Button is just a MouseArea, not a QML Button. This means there is no property Button.activeFocusOnPress that I could set to false. Is there a way to replicate this behaviour for the MouseArea?
Here's some code:
TextArea {
id: editor
width: parent.width
height: 200
anchors.top: pageHeader.bottom
anchors.bottom: toolbar.top
}
ListModel {
id: textNavButtons
ListElement {buttonText: "left"}
ListElement {buttonText: "right"}
ListElement {buttonText: "tab"}
ListElement {buttonText: "home"}
ListElement {buttonText: "end"}
}
Row {
id: toolbar
anchors.bottom: parent.bottom
width: parent.width
height: 80
Repeater {
id: toolbarRepeater
model: textNavButtons
property int modelCount: model.count
delegate: Button {
text: buttonText
width: parent.width / toolbarRepeater.modelCount
onClicked: {
console.log("I was clicked: " + text);
}
}
}
}
EDIT: My goal is to use these buttons to insert tabs into the text, or to navigate with Home, End, Left, Right etc. I'm not sure if using these buttons will achieve the goal, but I had no other idea. I will have to simulate the keypress too.

Now you can use
delegate: Button {
text: buttonText
width: parent.width / toolbarRepeater.modelCount
focusPolicy: Qt.NoFocus
onClicked: {
console.log("I was clicked: " + text);
}
}

Related

Why does my QML ListView overlap my Text in a Column positioner?

A Column positioner is supposed to position its children in a column. But when one of the children is a ListView, I find it overlaps the other children.
When the children are just Text's there's no overlapping and everything is fine.
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
visible: true
width: 640
height: 480
Column {
Text {
text: "Hello World"
}
// This works - appears under "Hello World"
Text {
text: "Hi Again"
}
// This doesn't - overlaps "Hello World" and "Hi Again"
ListModel {
id: theModel
ListElement { display: "one" }
ListElement { display: "two" }
ListElement { display: "three" }
}
ListView {
height:100
model: theModel
delegate: Text {
text: display
}
}
}
}
Expected result: Listview appears under "Hi Again"
Actual result: ListView overlaps "Hello World" and "Hi Again"
I often come a cropper with overlapping items in QML. Am I missing something fundamental that someone can explain to me? I'm having trouble finding a good reference book for QML positioning.
The Column (and other positioners for that matter) will not position items that are deemed invisible, the definition being height and width above zero and visible = false. This means you can easily solve it by anchoring the ListView to the left and right of it's parent:
ListView {
height:100
anchors.left: parent.left
anchors.right: parent.right
Component.onCompleted: console.log(implicitHeight, implicitWidth)
model: theModel
delegate: Text {
text: display
}
}

Reusable confirmation prompt in QML

I need a confirmation or alert dialog when user presses a button. Based on if they choose 'yes' or 'no', different actions are triggered. The challenge is that I have two buttons which pops such a dialog and it's not quite straightforward how to do that in QML. Here is the code (my demo application):
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
function areYouSure()
{
prompt.visible = true
}
MainForm {
anchors.fill: parent
Button {
id: buttonA
anchors.left: parent.left
anchors.top: parent.top
text: "Button A"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
Button {
id: buttonB
anchors.right: parent.right
anchors.top: parent.top
text: "Button B"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
}
Prompt {
anchors.fill: parent
id: prompt
visible: false
onCancelled: {
console.log("Cancel was pressed")
// but how can I tell which button's cancel as pressed?
}
onAccepted: {
console.log("Accept was pressed")
// same for which button's Ok?
}
}
}
Prompt.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Rectangle
{
id: root
width: parent.width
property string message: "Are you Sure?"
signal cancelled;
signal accepted;
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
cancelled()
}
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
accepted()
}
}
}
}
In traditional programming, an individual dialog pops up which respond exactly to that question and than we respond to its cancelled() or accepted() signals. In QML we can't really do that, right? What is the best way to know which button was pressed? The irony is that even the right signals are emitted, we just can't seem to act on them.
Well, first and foremost you should really have a look at Dialogs module since it provides what would be a ready made solution for you, i.e. MessageDialog.
That said, you can achieve a customisation in different ways, including redefining the handlers or passing the ids. If the action to perform are simple (e.g. a function call) you can dynamically create even the dialog and bind the signals with the desired behaviour. Customisation can obviously go further, changing title and text.
Here is a simple example which follows the last approach and prints different texts depending on the pressed button. Once the dialog is set to not visible it is destroyed via the destroy function.
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
ApplicationWindow {
id: win
title: qsTr("MultiDialog")
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
onClicked: {
var d1 = compDialog.createObject(win)
// change "title" & "text"?
d1.accepted.connect(function(){
console.info("accepted: " + text)
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
})
d1.visible = true
}
}
Button {
text: "Button 2"
onClicked: {
var d2 = compDialog.createObject(win)
// change "title" & "text"?
d2.accepted.connect(function(){
console.info("accepted: " + text)
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
})
d2.visible = true
}
}
}
Component {
id: compDialog
MessageDialog {
title: "May I have your attention please"
text: "It's so cool that you are using Qt Quick."
onVisibleChanged: if(!visible) destroy(1)
standardButtons: StandardButton.Cancel | StandardButton.Ok
}
}
}
If you want to use Rectangle or are forced to use it, then you can still use this approach. Dynamic creation of objects is NOT related to the usage of MessageDialog and can be used (and should be used) to reduce the number of objects kept instanced throughout application lifetime. Have a look here for more details about that.
The following example uses the very same dialog component you defined (with some small modifications. As you can see the code is almost identical. I've just moved the destruction of the object at the end of the signal handlers. In this case I've also changed the value of the unique property defined in the component, i.e. message, to show you complete customization.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component {
id: prompt
Rectangle {
id: root
anchors.fill: parent
property string message: "Are you Sure?"
signal rejected()
signal accepted()
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: rejected()
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: accepted()
}
}
}
}
}
If your component is not inlined as I did with Component but it's kept in another file you can use createComponent as depicted in the link provided above. The code of your main window would look like this:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
property var prompt
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component.onCompleted: prompt = Qt.createComponent("Prompt.qml");
}
You should always check that component creation is correcly carried out (I didn't do it for the sake of brevity). That said, the code is identical to the previous one.
Last but not least, I've noticed an error in your code: signals must always be declared with parenthesis, even when no parameter is emitted. It should be signal accepted(), not signal accepted, same goes for the other signal and any other signal declaration.

How to hide a QML Window when opening a other QML Window

I need to hide The QML Window when opening the another QML Window while clicking the button,I use Loader to open the another QML Window and its only hide the QML form components not QML Window,but I currently use window component to opens the QML Window
Here is my code :
Button {
id: button2
x: 19
y: 54
width: 114
height: 25
text: qsTr("DIFF-R")
style: ButtonStyle {
background: Rectangle {
implicitWidth: 10
implicitHeight: 25
border.width: control.activeFocus ? 2 : 1
border.color: "#555"
radius: 10
gradient: Gradient {
GradientStop { position: 0 ; color: control.pressed ? "#ddd" : "#fff" }
GradientStop { position: 1 ; color: control.pressed ? "#8ad993" : "#528dc8" }
}
}
}
onClicked:{
/*pagesource.source="screen2.qml"
button1.visible="false"
button2.visible="false"
text1.visible="false"
text2.visible="false"
text3.visible="false"
text4.visible="false"
textField1.visible="false"
textField2.visible="false"
textField3.visible="false"
image1.visible="false"*/
var component = Qt.createComponent("screen2.qml")
var window = component.createObject(root)
window.show("screen2.qml") }
The above code only navigates the QML Window while the Button is clicked whereas I need to Hide the QML Window.
I see no code when you hide main window. Please, read this article since your code say nothing about the problem.
This is small example when main window hides when popup shows. May be it can be useful for you.
Window {
id: mainWindow
title: "Main window"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Component {
id: popupWindow
Window {
title: "Popup window"
width: 400
height: 400
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Text {
anchors.centerIn: parent
text: "Close me to show main window"
}
}
}
Button {
anchors.centerIn: parent
text: "Show popup window"
onClicked: {
var window = popupWindow.createObject(mainWindow);
mainWindow.hide();
conn.target = window;
}
}
Connections {
id: conn
onVisibleChanged: {
mainWindow.show();
}
}
}

How to make TableView Items draggable

I’ve a TableView and have implemented my own item delegate for it. I want to be able to drag it out and place it somewhere else. How do I do it
itemDelegate: Text {
id: objMainText
anchors.horizontalCenter: parent.horizontalCenter
elide: styleData.elideMode
color: "yellow"
text: styleData.value.get(0).content //assume this is correct
MouseArea {
id: objDragArea
anchors.fill: parent
drag.target: objDragableText
drag.axis: Drag.XAndYAxis
hoverEnabled: true
onEntered: {
console.log("Hover Captured") //This gets printed
}
onClicked: {
console.log("Detected") //This NEVER gets printed
}
Text {
id: objDragableText
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.active: objDragArea.drag.active
opacity: Drag.active / 2
text: objMainText.text
color: objMainText.color
states: State {
when: { objDragArea.drag.active }
AnchorChanges {
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
}
}
}
Don’t mind if there are a few brackets less here and there. Those I’m taking care of ofcourse. But why can’t I drag objDragableText and how do i do it?
Also, onClicked is captured as in the comments above but not onPressed. How do I also do this?
{Qt 5.1 RC 1 - Win7 - MinGw 4.8}

Customized radio button in qml

I want a window with 3 push button but this push buttons should work like radio button!
so this is my code:
Rectangle {
id: sideButton
color: sideButtonMouseArea.containsMouse ? '#DDDDDD' : '#F4F4F4'
property string text: 'Button'
MouseArea {
id: sideButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
parent.color = '#4872E8'
sideButtonLabel.color = '#E2EBFC'
}
}
Text {
id: sideButtonLabel
text: sideButton.text
font.pixelSize: 20
font.family: 'Tahoma'
anchors.centerIn: sideButton
color: '#787878'
}
}
I use this rectangle instead button but it has a proble when click on other button for 2end time
how could i fix it?
This code works for me:
MyRadioGroup.qml
import QtQuick 1.0
QtObject {
property Item selected : null
}
MyRadioButton.qml
import QtQuick 1.0
Rectangle {
id: sideButton
property string text: 'Button'
property MyRadioGroup radioGroup
color: radioGroup.selected === sideButton ? '#E2EBFC' :
(sideButtonMouseArea.containsMouse ? '#DDDDDD' : '#F4F4F4')
MouseArea {
id: sideButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: sideButton.radioGroup.selected = sideButton
}
Text {
id: sideButtonLabel
text: sideButton.text
font.pixelSize: 20
font.family: 'Tahoma'
anchors.centerIn: sideButton
color: radioGroup.selected === sideButton ? '#E2EBFC' : '#787878'
}
}
main.qml
import QtQuick 1.0
Rectangle {
height: 600
width: 600
MyRadioGroup {
id: radioGroup1
}
Column {
anchors.fill: parent
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 1"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 2"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 3"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 4"
radioGroup: radioGroup1
height: 100
}
}
}
What it does: I've created container MyRadioGroup to hold currently selected item. Then, I declaratively bind its selected property with color property of my MyRadioButton-s, so it will update on every selected change.
Having that said, please check, that you component provider doesn't already contain some stuff like this --- maybe you are reinventing the wheel.