在qml中的使用StackView,編譯到手機後想通過back鍵進行pop操作,但是用正常的Keys過濾的時候由于StackView在pop的時候丢失焦點是以back鍵直接變成android預設的推出功能,然後就想用c++來寫一個過濾器來擷取Key_Back;
思路來源于http://www.mamicode.com/info-detail-1434390.html(原連結已跪,上個轉發的)
先看效果=============》
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下載下傳位址
點選打開連結