Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android back button press doesn't trigger keys.onreleased qml

I am creating a program in Qt5.3 and Qtquick2.1. I am trying to capture back button press on android in my code using Keys.onReleased. But that event is not getting triggered. Also I have set the item focus to true. But still no success. Here is the code sample

import QtQuick 2.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1

Rectangle
{
    id: main2
    focus: true
    width: Screen.Width
    height: Screen.Height
    Keys.enabled: true
    Keys.priority: Keys.BeforeItem

    property string load_page: ""
    signal deskConnected()

    Loader{
        id: pageloader
        anchors.fill: parent
        source: "qrc:/qml/resources/Firstpage.qml"
    }

    onDeskConnected: {
         pageloader.item.onDeskConnected()
    }

    function loadPatwin(){
        pageloader.source = "qrc:/qml/resources/Secondpage.qml";
    }

    Keys.onReleased: {
        console.log("back");
        if (event.key === Qt.Key_Back) {
            event.accepted=true;
        }
    }
}

Here loadPatwin is the function which gets called on pressing a button which is defined in some other qml. And loads a new qml. But after that when I am pressing the back button on android, the app gets closed and it doesn't print even "back" in the logs. Any suggestions what I am doing wrong here?

Thanks in advance.

like image 208
AmarSneh Avatar asked Sep 22 '14 07:09

AmarSneh


4 Answers

In qt quick (Qt5.1 and later) the ApplicationWindow and Window, both have a closing signal that is emitted when the user touches the back button in android. You can simply implement an onClosing handler and set the close parameter to false. Here is how to do it:

onClosing: {
    close.accepted = false
}

By this handler you can easily manage the back button of android device. It does not need any extra permission. For example suppose you have a StackView to manage the GUI. You can write these lines of code, Then your application behaves as like as a native android app:

onClosing: {
        if(stack.depth > 1){
            close.accepted = false
            stack.pop();
        }else{
            return;
        }
    }
like image 128
a.toraby Avatar answered Oct 24 '22 16:10

a.toraby


It works for me by adding "forceActiveFocus()" after the item has completed loading.

In your example I would put it at the beginning. Like this:

Rectangle
{
    id: main2
    focus: true

    Component.onCompleted: {
        main2.forceActiveFocus()
    }
like image 37
Tony Avatar answered Oct 24 '22 15:10

Tony


I don't know whether this is a good example, but I used to create my own GuiApplication class subclassing from QGuiApplication

#ifndef GUIAPPLICATION_H
#define GUIAPPLICATION_H

#include <QGuiApplication>

class GuiApplication : public QGuiApplication
{
    Q_OBJECT
public:
#ifdef Q_QDOC
    explicit GuiApplication(int &argc, char **argv);
#else
    explicit GuiApplication(int &argc, char **argv, int = ApplicationFlags);
#endif

    bool notify(QObject *receiver, QEvent *event);
signals:
    void back();

};

#endif // GUIAPPLICATION_H

This is for cpp codes

#include "guiapplication.h"
#include <QDebug>

GuiApplication::GuiApplication(int &argc, char **argv, int) :
    QGuiApplication(argc, argv)
{
}

bool GuiApplication::notify(QObject *receiver, QEvent *event)
{
// to intercept android's back button
#ifdef Q_OS_ANDROID
    if(event->type() == QEvent::Close) {
        emit back();
        return false;
    }
    else {
        return QGuiApplication::notify(receiver,event);
    }
#else
        return QGuiApplication::notify(receiver,event);
#endif
}

For main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "guiapplication.h"

int main(int argc, char *argv[])
{
//    QGuiApplication app(argc, argv);
    GuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    QQmlContext *rootContext = engine.rootContext();
    rootContext->setContextProperty("GUI", &app);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

and finally for main.qml

import QtQuick 2.3
import QtQuick.Controls 1.2

ApplicationWindow {
    id: applicationWindow

    visible: true
    width: 360
    height: 360

    Connections {
        target: GUI
        onBack: console.log("back")
    }
}
like image 1
fpermana Avatar answered Oct 24 '22 17:10

fpermana


I've just stumbled upon this problem myself, but the proposed solution of handling the closing signal of Window or ApplicationWindows is more of a workaround than a solution. While it might work fine for Android, any cross-platform application will then employ "back"-button handling when you actually want to close the window (e.g. press the the "x" button on the window title bar)

To do this correctly, we have to keep in mind how key event handling in QtQuick happens: The item with activeFocus gets the event first. If it doesn't handle the event, it is propagated to it's parent item. This goes on until it reaches the root item. Here's the crux: Window or ApplicationWindow are the outermost object, but they're not Item-based! The root Item is actually Window::contentItem. This is where you need to install a Keys handler to receive all non-handled key events, including Back button presses. Unfortunately, attached properties don't work for read-only object-typed properties, so we have to do this imperatively in onCompleted:

ApplicationWindow {
    id: window

    Component.onCompleted: {
        // Connect to `released` signal and dispatch to `back()`
        contentItem.Keys.released.connect(function(event) {
            if (event.key === Qt.Key_Back) {
                event.accepted = true
                window.back()
            }
        })
    }

    function back() {
        // Back button handling goes here
    }
}
like image 1
pumphaus Avatar answered Oct 24 '22 16:10

pumphaus