qml在stackView的情况下处理Android back键(返回键)全局双击back键退出程序

在qml中的使用StackView,编译到手机后想通过back键进行pop操作,但是用正常的Keys过滤的时候由于StackView在pop的时候丢失焦点所以back键直接变成android默认的推出功能,然后就想用c++来写一个过滤器来获取Key_Back;

思路来源于http://www.mamicode.com/info-detail-1434390.html(原链接已跪,上个转发的)

先看效果=============》qml在stackView的情况下处理Android back键(返回键)全局双击back键退出程序_第1张图片

1、在qml中正常处理Key_back

方法什么说的没什么说的,需要注意的是正常键盘事件需要获取焦点,如果焦点丢失那么事件也不会接受到,在StackView中遇到的问题就是这个原因,下面贴写正常的代码

 Rectangle{
        anchors.fill: parent;
        color:"lightgreen";
        Keys.onPressed: {
            if (event.key == Qt.Key_Back) {
                        event.accepted = true;
             }
        }
        focus:true;//必须要有焦点
    }

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2、用c++处理

2.1

首先qt c++ QObject派生出来的类中都有过滤事件,我们只要继承一个QObject的类重写下过滤函数就能实现消息的过滤

[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)//过滤的虚函数

2.2

然后将其写成单例模式(方便qml中的信号链接),添加一个sig_KeyBackPress()信号用来通知qml back键被按下

KeyFilter类实现如下

KeyFilter.h

#include 


class KeyFilter : public QObject
{
    Q_OBJECT
public:

    static KeyFilter* GetInstance();
    explicit KeyFilter(QObject *parent = 0);
    //设置过滤对象
    void SetFilter(QObject *obj);
protected:
    //事件过滤
    bool eventFilter(QObject *watched, QEvent *event);
private:

signals:
    void sig_KeyBackPress();
    void sig_AppExit();
public slots:

};
KeyFilter.cpp

#include "KeyFilter.h"
#include 
#include 
#include 

KeyFilter::KeyFilter(QObject *parent) : QObject(parent)
{

}
//单例
KeyFilter* KeyFilter::GetInstance()
{
    static QMutex mutex;
    static QScopedPointerinstance;
    if(Q_UNLIKELY(!instance))
    {
        mutex.lock();
        if(!instance)
        {
            instance.reset(new KeyFilter);
        }
        mutex.unlock();
    }
    return instance.data();
}


bool KeyFilter::eventFilter(QObject *watched, QEvent *event)
{
    //获取事件类型
    if(event->type() == QEvent::KeyPress)
    {
        //转换成键盘事件
        QKeyEvent *keyEvent = static_cast(event);
        //判断是否是back事件
        if(keyEvent->key() == Qt::Key_Back)
        {
            //发送back键按下的信号
            emit sig_KeyBackPress();
            return true;
        }
    }
    return false;//
}

void KeyFilter::SetFilter(QObject *obj)
{
    //将过滤器注册到对应的类
    obj->installEventFilter(this);
}


2.3

在main.cpp中将过滤器注册为QML的基本类型,通过QQmlComponent来获取对象,然后给对象添加过滤器。

#include 
#include 
#include 
#include 
#include "KeyFilter.h"

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

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("keyFilter", KeyFilter::GetInstance());
    QQmlComponent component(&engine, QUrl("qrc:/main.qml"));
    //获取对象
    QObject *object = component.create();
    //添加过滤器
    KeyFilter::GetInstance()->SetFilter(object);
    return app.exec();
}

2.4

接下来就是qml中的操作啦!具体处理就不多说了直接看代码
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4



Window {
    //用来自适应android
    property real multiplierH: (mainWindow.height/640)*1000;
    property real multiplierW: (mainWindow.width/360)*1000;
    function dpH(numbers) {
       return numbers*multiplierH/1000;
    }
    function dpW(numbers) {
        return numbers*multiplierW/1000;
    }
    function dpX(numbers){
        return (dpW(numbers)+dpH(numbers))/2;
    }

    id:mainWindow;
    visible: true
    width: 360
    height: 640
    title: qsTr("Hello World")
    //标记back是否被按下(如果true再次接受到按下消息后将退出app)
    property bool backPressed: false;



    //链接过滤器信号
    Connections{
        target:keyFilter;
        onSig_KeyBackPress:{
            //如果stackview不是在根节点就pop不标记接受到back信号
            if (stackView.depth > 1)
            {
                stackView.pop();
            }
            //第一次接受到back
            else if(!backPressed)
            {
                //启动一个定时器,在定时器结束后没收再次收到back信号就将back标记初始化
                timer.start();
                backPressed = true;
                //启动提示动画
                back_animation.start();
            }
            //在 一定时间没连续收到back信号
            else if(backPressed)
            {
                Qt.quit();
            }
        }
    }
    //定时器
    Timer{
        id:timer;
        interval: 3000;
        triggeredOnStart: false;
        onTriggered: {
               backPressed = false;
               timer.stop();
        }
    }
    MouseArea{
        anchors.fill: parent;
        onClicked: {
            if (stackView.depth < 2)
            {
                var pageTwo = Qt.createComponent("PageTwo.qml");
                stackView.push(pageTwo);
                console.log("depth = "+stackView.depth);
            }

        }
    }

    StackView{
        id: stackView;
        anchors.fill: parent;
        focus: true;
        initialItem: "qrc:/PageOne.qml";
    }
    //退出的消息框
    Rectangle{
        id:exit_rect;
        radius: dpX(20);
        z: 10;
        width: dpW(130);
        height: dpH(30);
        color:"black";
        opacity:0;
        anchors.centerIn: parent;
        Text{
            anchors.centerIn: parent;
            text:qsTr("再按一次退出");
            color: "white";
            font.pixelSize: dpX(15);
            z:10;
        }

    }
    //退出提示的动画
    SequentialAnimation{
        id:back_animation;

        NumberAnimation {
            target: exit_rect;
            property: "opacity";
            duration: 1000;
            to:100;
            easing.type: Easing.InCubic;
        }
        NumberAnimation {
            target: exit_rect;
            property: "opacity";
            duration: 1000;
            to:100;
            easing.type: Easing.InOutQuad;
        }
        NumberAnimation {
            target: exit_rect;
            property: "opacity";
            duration: 1000;
            to:0;
            easing.type: Easing.InOutQuad;
        }

    }

}

3、这样我们就实现了StcakView back键的返回,以及正常目录下双击back退出程序

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


4、最后上下demo下载地址

点击打开链接


你可能感兴趣的:(qml)