Clicking back button twice to exit from application in qml? - qt

How to exit from an application by clicking the back button twice on your mobile?
for going back to the previous page i have done this
Keys.onBackPressed: {
stackView.push("previous.qml")
}

Keys.onBackPressed: {
timer.pressBack()
}
Timer{
id: timer
property bool backPressed: false
repeat: false
interval: 200//ms
onTriggered: backPressed = false
function pressBack(){
if(backPressed){
timer.stop()
backPressed = false
// leave application
// your code
leaveApp()
}
else{
backPressed = true
timer.start()
}
}
}
You can use a timer to do this, within 50ms if you press twice on back this will run leaveApp().

Related

Pass parameter to MessageDialog to process it further based on user interaction with dialog

There is this QML message dialog:
MessageDialog {
id: questionDialog
icon: StandardIcon.Question
standardButtons: StandardButton.Yes | StandardButton.No
title: qsTr("Question") + editorScene.emptyString
text: qsTr("Do stuff?") + editorScene.emptyString
onYes: {
console.log("I want to be able to process parameter here")
}
onNo: {
console.log("Do nothing")
}
}
Inside a onParameterChanged slot, I open the dialog while handing a parameterChanged signal. This signal passes a parameter:
onParameterChanged: {
if (parameter) { // "parameter" is passed by parameterChanged signal
questionDialog.open() // How can I pass "parameter" to dialog when opening it?
}
}
Now I wonder how it is possible to pass parameter from onParameterChanged slot to question dialog to be able to process parameter if user selects Yes button.
Problem solved by using Property Attributes.
I defined a new property attribute for MessageDialog:
MessageDialog {
id: questionDialog
property string parameterName: ""
onYes: {
console.log("Parameter to be processed:", parameterName)
}
}
Then I set the property attribute before opening the dialog:
onParameterChanged: {
if (parameter) { // "parameter" is passed by parameterChanged signal
questionDialog.parameterName = parameter // Set property attribute
questionDialog.open()
}
}

How to store button value by pushing only once

I am trying to make a program that stores my button digital input so that I don't have to keep holding the button for it to work.
The algorithm I am trying to develop is when the button is pressed, it it executes the servoMomvement() function then increments count by one. If count is even then program runs, but then if the button is pressed again it will not be even and would stop working.
void loop() {
while(true){
int count = 0;
bool isEven = count%2;
bool condition = digitalRead(4);
if(condition == true && isEven == false){
servoMovement();
count++;
}
}
}
It is not working as intended. I still have to hold to push button for it to not stop executing.
You can use timer to incremenet count by one.This timer function check periodically button. And when you press it will work as you want. But first of all you have to know timers ability and capacity.
The problem is that the loop method is executed in a loop (like one could guess by the name of the method...) and therefore it's checked in every loop whether the button is pressed.
Because in your if statement it says condition == true && ... this will only be true if the condition is true (the button is pressed).
If I understood your question correctly you want to have some kind of start-/stop-button. If so you could try like this:
//global variable run
bool run;
void setup() {
run = false;
}
void loop() {
while(true){
bool condition = digitalRead(4);
if (condition) {
run = !run;//switch the state of the run variable
delay(50);//some delay to debounce the button; see https://www.brainy-bits.com/arduino-switch-debounce/ for more information
}
if(run){
servoMovement();
}
}
}
I have a quite simple solution for that.
You can compare the actual buttonstate with the buttonstate the "round" before.
bool Button = false;
bool ButtonBefore = false;
bool help = false;
void loop()
{
Button = digitalRead(ButtonPin);
if(Button > ButtonBefore) help = !help;
if(help) { do stuff; }
ButtonBefore = Button;
}
When you press the button, "Button" becomes true while "ButtonBefore" is still false. So "Button" is bigger than "ButtonBefore" so "help" changes to true. In the next cycle "ButtonBefore" is even to "Button" so "help" won't change its state. When the button is released, "ButtonBefore" is bigger than "Button" so it "help" won't change too. So the state from "help" is changed when the button is pressed.
I hope I could help you with this.

Xamarin.Forms UI Test - Tap Button multiple (5) times

I'm working on writing an UI-Test for my Xamarin.Forms Application.
Therefore I need to tap a button 5-times. This invokes a dialog and I need the result of the user's input to this dialog.In code I realised this by implementing an GestureRecognizer:
private bool HandleMultipleTouch()
{
if (iLastTap == null || (DateTime.Now - iLastTap.Value).Milliseconds < iToleranceInMs)
{
if (NumberOfTaps == 4)
{
NumberOfTaps = 0;
iLastTap = null;
return true;
}
else
{
NumberOfTaps++;
iLastTap = DateTime.Now;
return false;
}
}
else
{
NumberOfTaps = 0;
iLastTap = null;
return false;
}
}
Do you know any method how to use Xamarin.UITest to get the button taped 5 times in a short time?
I tried used double tap twice and one single tap, but this is not working because of the time needed to execute the taps.
I had a similar issue, where I had to tap a morse code using Xamarin.UITest and concluded that it's impossible to ensure consistent timing between taps. My solution was therefore to abandon the morse code and only check in the app whether the button was hit 5 times.

Is it possible to disconnect all slots from a signal in Qt5 QML?

In QML it is impossible to call .disconnect() without arguments for a signal:
file:mainwindow.qml:107: Error: Function.prototype.disconnect: no arguments given
So how can I disconnect ALL slots without specifying each of them?
Or maybe it is possible by passing signal object to C++ and disconnect it somehow there?
Or maybe any workaround exists?
The goal I want to reach is to change behavior of an object by connecting different slots to it's signal. For example:
object.disconnect() // disconnect all slots
object.connect(one_super_slot)
object.disconnect() // disconnect all slots
object.connect(another_super_slot)
No. I looked at the source code in qv4objectwrapper.cpp, and you can see this code:
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
{
engine->functionClass->prototype->defineDefaultProperty(QStringLiteral("connect"), method_connect);
engine->functionClass->prototype->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect);
}
Those are the only two methods that are added. If you look at the source code for method_disconnect() you can see that it always requires one or two parameters, including the name of the slot to disconnect.
There is no disconnectAll() unfortunately.
Okay, 5 minutes after my question I've made a workaround: connect only once to one signal that calls jsobject from inside:
Item {
property var fire
// Any qml object. In this example it is ActionExecutor which emits actionRequest
ActionExecutor {
//signal actionRequest(int actionType)
onActionRequest: fire(actionType)
}
Action {
shortcut: "Ctrl+S"
text: "One action"
onTriggered: {
parent.fire = function(actionType) {
console.log('one slot')
}
}
}
Action {
shortcut: "Ctrl+X"
text: "Another action"
onTriggered: {
parent.fire = function(actionType) {
console.log('Another slot')
}
}
}
}
So that js object can be reassigned many times as you want so you may change your behavior by reassigning this object. If you want to disconnect all simple assign undefined to fire. Also you can make a chain of "slots" by modifying code to something like:
Item {
property var fire
property var slots: [
function(actionType) {
console.log('1: ' + actionType)
},
function() {
console.log('2: ' + actionType)
},
function() {
console.log('3: ' + actionType)
}
]
// Any qml object. In this example it is ActionExecutor which emits actionRequest
ActionExecutor {
//signal actionRequest(int actionType)
onActionRequest: fire(actionType)
}
Action {
shortcut: "Ctrl+S"
text: "One action"
onTriggered: {
parent.fire = function(actionType) {
console.log('calling all custom JS-slots')
for (var i in slots) {
slots[i](actionType)
}
}
}
}
}
So anyone can implement own signal-slot architecture in qml as a simple javascript observer pattern.
Enjoy.

Stopping a behavior - QML

I program a "game" where a ball is sent to bounce against the walls.
Before hurt the walls, the behavior on y is a spring animation. When it hurt the wall, the ball should bounce and have a linear movement.
My problem is I can't stop the initial Behavior.
I have tried several way :
disabled the behavior but the movement in progress continue
stop the SpringAnimation : I have the error : " QML SpringAnimation: setRunning() cannot be used on non-root animation nodes."
This is the code
Rectangle {
id: ball
property bool enableMoving: false
function newMousePos(mX,mY){
if(enableMoving){
ball.x = mX - ball.width/2
ball.y = mY - ball.height/2
}
}
Behavior on x {enabled: true;id: behavX; SpringAnimation {id:spX; spring: 0.8; damping: 0.9; mass: 10; } }
Behavior on y {enabled: true;id: behavY; SpringAnimation {id:spY; spring: 0.8; damping: 0.9; mass: 10 ; } }
onXChanged: {
if(ball.x>main.width-ball.size) {
console.log("wall 2 ")
spX.stop(); spY.stop()
}
if(ball.x<0) {
...
}
}
onYChanged: {
...
}
Timer{
id:timerDisableMoving
interval: 500; running:true
onTriggered: enableMoving=false
}
}
I don't understand why I can't stop the behavior. Is it possible to define behavior on state to solve the problem ?
Put this code on signal when ball hits wall:
behavX.enabled = false
This will disable behavior (I have tested it in my project).
If you only want to disable specific animation then do it like this:
spX.running = false //ignore this, it is equivalent to spX.stop()
I just thought that you might putted code like this:
function disableBehavior()
{
behavX.enabled = false
//...
behavX.enabled = true
}
If this is the case, then it wont work because during the time of execution animation wont happen.
Instead, you should do asynchronous call, for example like this:
function disableBehavior()
{
behavX.enabled = false
//...
myTimer.start()
}
//...
Timer
{
id: myTimer
interval: 1
running: false
onTriggered:
{
behavX.enabled = true
stop()
}
}
But, I think that you will want to call "behavior enabler" after your "linear behavior" is finished (instead of creating new timer).
I think, I had similar problem. I had some Behavior, which animated change of some property. And I wanted to be able to stop it in the middle, while it did not yet complete.
It did not work. By the way, QML also was complaining in the console, that I try to use some method on non-root Animation.
The short answer:
It seems, that it is not supported by the Behavior to be stopped in the middle.
Though, it can be interrupted by setting new value to the property. This would restart the animation to target the new value. When I realized it, I implemented the "stop" function like this:
function stopAnimation() {
// disable animation for the next value change
moveBehavior.enabled = false
// Change value of the property of interest.
// This stops currently running animation
y += 1
// Restore initial value of the property
y -= 1
// Enable animation for subsequent property changes
moveBehavior.enabled = true
}
So, I disable the behavior to make the change of properties instant. Then I change target property to something very close to the current value (I believe, I cannot use the same value, because then "onChange" signal will not be emitted). At this point running animation should be stopped. Then I reset property to its original value. And then enable animation again to handle further property changes.
Looks not that good, but it worked for me with Behavior...
After thinking a bit more I come to the conclusion, that I probably should not use Behavior. Then I just created PropertyAnimation{} tied to my property of interest directly in the object, which needs to be moved. And then I just dynamically assign target value and duration and with now "start()" and "stop()" just work as expected.
Full solution looks like this (what it does, you can probably figure out):
Item {
id: root
focus: true
Rectangle {
id: racket
height: 40
width: 10
x: 20
y: 20
color: "blue"
property int maxY: 460
// ...
PropertyAnimation {
id: moveDownAnimation
target: racket
property: "y"
to: racket.maxY
// if you want constant velocity, you need
// to calculate duration dynamically based
// on desired velocity and distance
duration: 1000
}
function moveUp () { // just return racket to the initial position
y = 50
}
function moveDown() {
moveDownAnimation.start()
}
function stopAnimation() {
moveDownAnimation.stop()
}
}
Keys.onPressed: {
if (event.isAutoRepeat) {
return
}
if (event.key === Qt.Key_Q) {
racket.moveUp() // return to initial position
} else if (event.key === Qt.Key_A) {
racket.moveDown()
}
}
Keys.onReleased: {
if (event.isAutoRepeat) {
return
}
if (event.key === Qt.Key_A) {
racket.stopAnimation()
}
}
}

Resources