Qml TextEdit Custom key event not processed properly - qt

I wanted to add custom key events to a TextEdit. But, it seems key events are not properly processed inside TextEdit.
For example, in the code below, I am trying to handle Space key events. Although the Space keypress is recognized by the signal handler function, the output text does not contain a space. It is the same for all other key events. How do I overcome this?
import QtQuick 2.15
import QtQuick.Controls 2.15
Item{
function processSpace(event){
event.accepted = true
console.log(xTextEdit.text)
}
TextEdit{
id: xTextEdit
height: parent.height
width: parent.width
Keys.onSpacePressed: processSpace(event)
}
}

You accept the event, and thus prevent the default handling.
Set event.accepted = false instead, so the event will be propagated.
Note that accepted is by default true (at least for key events), so not setting it will the accept the event

Related

TextArea, process each character one at a time

I have a text area and I want to listen to every characters inputted on it,
What I am trying to do is when a spacebar is pressed, I will perform an operation or processing such as replacing some characters on it.
I have tried and listen to onTextChanged however, it may cause recursion as setting my TextArea.text to new value triggers a call to onTextChange event thus causing Stack Overflow.
I have tried to listen to Keys.onPressed event as well and listen to space key but the space key is processed as well and when I set a new text value, the space value is forcedly inserted.
How and where should I handled and listen to these events?
How can I listen to each inputted characters in QML text area, catch the space bar, process, and replace the text with the new processed text? Also ignore the last spacebar entry?
How do I reject a chracter when inputted in the TextEdit or TextArea?
Can you use TextInput which helps you differ whether text is changed by user or programmatically ?
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
TextInput
{
width: 200
height: 100
onTextEdited:
{
if( text[text.length-1] === " " )
{
text = process(text)
}
}
anchors.centerIn: parent
}
function process(textinput)
{
return textinput.toUpperCase()
}
}

qt qml checkbox: How to execute code when clicked by user but not checked by q_property binding

I have a checkbox in qt which I'd like to be checked via a q_property tied to code, but also by a user. When a user clicks on the checkbox, I'd like to run some code. The issue is that the onChecked callback seems to be called when the checkbox is checked via code as well as user input. This code would involve the checkbox being checked by code at a later time, which would trigger the onChecked callback. How is this situation best handled with the callbacks provided by Qt?
For more background if the above doesn't make sense: This checkbox controls a feature on a robot over a network connection, but it should also show the state of the feature since it could be enabled automatically or from a previous session. The q_property robotStatus.missionLooping is set by a periodic status update. When the user checks the box, it should trigger a network call to enable the feature, and then the status update will happen a moment later which would see that the feature is enable and check the box (Even though it's already checked).
AppCheckBox.qml:
import QtQuick 2.15
import QtQuick.Controls 2.15
CheckBox
{
id: root
indicator: Rectangle
{
implicitWidth: utilities.dp(40)
implicitHeight: utilities.dp(40)
x: root.leftPadding
y: parent.height / 2 - height / 2
Rectangle
{
width: utilities.dp(20)
height: utilities.dp(20)
x: utilities.dp(10)
y: utilities.dp(10)
radius: utilities.dp(3)
color: theme.green
visible: root.checked
}
}
contentItem: Text
{
text: root.text
font: root.font
opacity: enabled ? 1.0 : 0.3
color: theme.white
verticalAlignment: Text.AlignVCenter
leftPadding: root.indicator.width + root.spacing
//font.pointSize: constants.coordinatesTextPointSize + 1
minimumPointSize: constants.minimalCoordinatesTextPointSize
}
}
ui.qml:
AppCheckBox
{
id: missionLoopingCheckbox
enabled: isConnected
checked: robotStatus.missionLooping
text: qsTr("Mission Looping")
}
You can implement onToggled signal handler. toggled signal is emitted when a checkable button is interactively toggled by the user via touch, mouse, or keyboard.
I'm assuming below that robotStatus.missionLooping is a readonly property. You need Q_INVOKABLE method or a slot function to call e.g. robotApi.loopMission(bool) which calls robot over the network and in turn causes robotStatus.missionLooping property to change to true/false when looping starts/stops.
AppCheckBox
{
id: missionLoopingCheckbox
enabled: isConnected
checked: robotStatus.missionLooping
text: qsTr("Mission Looping")
onToggled: {
robotApi.loopMission(missionLoopingCheckbox.checked)
}
}

TextInput documentation don't specify onTextChanged signal

I can subscribe to the signal TextChanged in my QML code. But however i don't seem to find it in the documentation. I've searched the inherited ascending classes as well, none of them specify it. Have I missed something or is the documentation wrong?
I'm running QtQuick 2.15 and looking in the documentation for QtQuick 2.15 TextInput QML Type
TextInput {
id: firstNameInput
onTextChanged: {
console.log("First name: " + text)
}
}
I found the problem I've forgot that all the properties are assigned with handlers in QT.
import QtQuick 2.15
TextInput {
// Property
text: "Change this!"
// Signal handler
onTextChanged: console.log("Text has changed to:", text)
}

Binding Type: Is it possible to listen to a temporarily overridden binding?

I'd like to create a widget that has a value that can be bound to a value outside of itself, but can also internally set this value. A scenario I'd like to be able to support:
Developer using the widget binds the widget's value to some external value
At run-time, widget value follows any external value changes via this binding
User interacts with widget, setting their own value
Some time later, external value is updated
Ideally, widget value would then return to being bound to the external value
Point 5 does not seem possible when using only bindings. Here is an example where 'textItem' is our imaginary widget:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
property real externalValue: (Math.random()* 50).toFixed(0)
Timer {
running: true
repeat: true
interval: 1000
onTriggered: {
// Simulate externalValue changes out of our control
externalValue = (Math.random()* 50).toFixed(0)
}
}
Component.onCompleted: {
// Unknown external binding set by developer using textItem widget
textItem.text = Qt.binding(function(){return externalValue})
}
Column {
Text {
id: textItem
text: ""
property real internalValue: (Math.random()* 50).toFixed(0)
Binding on text {
id: binding
value: textItem.internalValue
when: false
}
}
Button {
text: "Change Internal Value"
onClicked: {
textItem.internalValue = (Math.random()* 50).toFixed(0)
binding.when = true
}
}
}
}
So textItem.text listens to the externalValue binding until a user interacts with the button, which then binds textItem.text to the user-set internal value. Assuming textEdit is a black-box widget, and it has no concept of externalValue before its runtime binding, is there any way for textEdit to internally listen to the overridden externalValue binding and restore it (by setting binding.when = false) the next time that externalValue is updated by the timer?
One way to make the scenario work would be to use direct assignments in place of all of the bindings, but this seems like it would cause a confusing widget API since I can't stop users from trying to use bindings which would confusingly get broken by the widget's black-box internal assignments...
You can temporarily override bindings using States, like in the code below.
The real problem here is detecting when the external value has changed, in my solution I'm using a Timer for this, but your requirements ask for the external value to change again. Since you are externally binding to property text and also overriding the binding to text you temporarily loose the change signals from the external binding, hence cannot undo the temporary binding.
If you have control over the widget, I would implement a property which should be set externally and internally assign that value to where it should go. This gives you the ability to receive the changes and for example stop the tempBoundedTimer (Since I still think you should have a timer to not indefinitely override the binding in case the external value fails to update).
If you don't have control over the widget, I would settly down on a suitable interval for tempBoundedTimer
(In any case, I don't adding a Timer in each instance of the widget is very nice)
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
property real externalValue: (Math.random()* 50).toFixed(0)
Timer {
running: true
repeat: true
interval: 1000
onTriggered: {
// Simulate externalValue changes out of our control
externalValue = (Math.random()* 50).toFixed(0)
}
}
Component.onCompleted: {
// Unknown external binding set by developer using textItem widget
textItem.text = Qt.binding(function(){return externalValue})
}
Column {
Text {
id: textItem
text: ""
property real internalValue: (Math.random()* 50).toFixed(0)
Timer {
id: tempBoundedTimer
repeat: false
interval: 2000
}
states: [
State {
when: tempBoundedTimer.running
PropertyChanges {
target: textItem
text: "internal:" + internalValue
}
}
]
}
Button {
text: "Change Internal Value"
onClicked: {
textItem.internalValue = (Math.random()* 50).toFixed(0)
tempBoundedTimer.start()
}
}
}
}
BTW, I think your Binding object should actually also work if the when is bound to tempBoundedTimer.running, but I couldn't get it to play nice. It seems the Qt.binding has priority

QtQuick - button onClick event

Background story
So I recently decided that I should try out Qt. I started making a QtQuick Apllication. In my designer view I have one button and a mouse area.
What I want to do:
When I click the button, I want to display a message box with some text (like "Hello World").
My Question
How can I do that ?
Additional info
I tried googling it, i tried following this answer. But still nothing.
I know how to program in .Net (C# and VB), i have some knowage in C/C++, but Qt seems to hard for me
How about this:
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.1
Rectangle {
width: 360
height: 360
MessageDialog {
id: msg
title: "Title"
text: "Button pressed"
onAccepted: visible = false
}
Button {
text: "press me"
onClicked: msg.visible = true
}
}
And if you prefer to have the dialog dynamically instantiated with arbitrary properties rather than have it "hardcoded", follow the first snippet from this answer. You can also set properties in createQmlObject() and instead of hiding the dialog just use destroy() to delete it.
You have to use signals and slots in order to trigger an event. You could use a QMessageBox that pops up to display Hello world.

Resources