安卓返回按钮按下不会触发 keys.onReleased QML。

8
我正在使用Qt5.3和Qtquick2.1创建一个程序。我试图在我的代码中使用Keys.onReleased捕获Android上的后退按钮,但该事件未被触发。我已将项焦点设置为true,但仍然没有成功。以下是代码示例。
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;
        }
    }
}

这里的loadPatwin是在按下由其他qml定义的按钮时调用的函数,它加载了一个新的qml。但之后当我在安卓上按返回按钮时,应用程序会关闭,并且日志中甚至没有打印“back”。请问我做错了什么?

先感谢您的帮助。


是的,它不起作用,我也尝试了一切,如果你有任何提示,请告诉我。 - JNI_OnLoad
JNI_OnLoad。 明白了。问题出现在使用QApplicationengine从main.cpp加载main.qml时。请改用QQuickview来加载main.qml文件。 - AmarSneh
不是我的情况,因为我正在使用QQuickView来加载main.qml,我想我的应用程序中还缺少一些东西。 - JNI_OnLoad
你是在qml还是cpp中处理返回按钮事件的? - AmarSneh
在 QML 中,我正在从堆栈视图中推送的组件中。 - JNI_OnLoad
5个回答

17

在Qt Quick(Qt5.1及更高版本)中,ApplicationWindowWindow都有一个closing信号,在Android上当用户按下返回按钮时会发出。您可以简单地实现一个onClosing处理程序,并将关闭参数设置为false。以下是实现方法:

onClosing: {
    close.accepted = false
}

通过这个处理程序,您可以轻松管理Android设备的返回按钮。它不需要任何额外的权限。例如,假设您有一个StackView来管理GUI。您可以编写以下代码行,然后您的应用程序的行为就像本机Android应用程序一样:

onClosing: {
        if(stack.depth > 1){
            close.accepted = false
            stack.pop();
        }else{
            return;
        }
    }

谢谢。这正是我一直在寻找的东西。 - Hyndrix
当我使用Qt 5.7和QtQuick.Window 2.2时,它会提示“onClosing属性名无效”... - Chris Flesher
实际上,即使编程界面标记为错误,使用您的onClosing解决方案似乎也可以正常运行...非常奇怪。 - Chris Flesher
@ChrisFlesher onClosing事件将发生在ApplicationWindow或Window对象中,这应该是您的main.qml的父组件。 - Derek Nowicki
我需要做的是将close.accepted = false语句移到if语句之前,以防止在堆栈位于底部时后退按钮关闭应用程序。非常好的解决方案! - Derek Nowicki
这只是一个权宜之计。在每个平台上,当窗口关闭时,即使在Windows、Linux或macOS的标题栏中按下“x”,也会触发closing事件。该事件应该由Keys处理,但需要安装在Window::contentItem上。请参见下面的示例回答:https://dev59.com/54Pba4cB1Zd3GeqPupoE#67357598 - pumphaus

5

在项目加载完成后,通过添加 "forceActiveFocus()" 代码可以解决我的问题。

在你的例子中,我会把它放在开头。像这样:

Rectangle
{
    id: main2
    focus: true

    Component.onCompleted: {
        main2.forceActiveFocus()
    }

1

我不知道这是否是一个好的例子,但我曾经创建过自己的GuiApplication类,继承自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

这是关于 C++ 代码的。
#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
}

对于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();
}

最后,针对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")
    }
}

1
我刚刚遇到了这个问题,但是处理WindowApplicationWindowsclosing信号的建议解决方案更像是一种变通而不是解决方案。虽然它在Android上可能运行良好,但任何跨平台应用程序在您实际想要关闭窗口时(例如按窗口标题栏上的“x”按钮)将使用“返回”按钮处理。
为了正确地实现这一点,我们必须记住QtQuick中关键事件处理的方式:具有activeFocus的项目首先接收事件。如果它无法处理该事件,则将其传播到其parent项目。这将继续进行,直到达到根项目。这是关键:WindowApplicationWindow是最外层的对象,但它们不是基于Item的!根Item实际上是Window::contentItem。这就是您需要安装Keys处理程序以接收所有未处理的键事件(包括Back按钮按下)的位置。不幸的是,对于只读对象类型属性,附加属性不起作用,因此我们必须在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
    }
}

这非常精准,为你找到真正的解决方案而鼓掌,而不是一个笨拙的方法。 - LorenDB

-1
在 QML 中,=== 是布尔比较。
因此,你应该使用 (event.key == Qt.Key_Back) 而不是 (event.key === Qt.Key_Back)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接