天天看點

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、在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 <QObject>


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 <QKeyEvent>
#include <QDebug>
#include <QMutex>

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

}
//單例
KeyFilter* KeyFilter::GetInstance()
{
    static QMutex mutex;
    static QScopedPointer<KeyFilter>instance;
    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<QKeyEvent*>(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 <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QDebug>
#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下載下傳位址

點選打開連結

繼續閱讀