2017-01-27 71 views
1

我使用Qt 5.6.2(Windows 10)並且有一個QObject衍生的映射器,它將QKeyEvent發送到當前關注的QML項目。我的基類有一個虛擬的mapToKey()函數,然後在我想要使用的各種映射器中重寫。例如下面的映射函數是我LeftArrowMapper的一部分,併發送左箭頭鍵事件:QML ListView和按鍵導航 - 處理單個按鍵事件

void LeftArrowMapper::mapToKey() 
{ 
    // Retrieve root of QML context 
    QObject* root = engine->rootObjects()[0]; 
    // Get currently focused item 
    QQuickItem *item = (root->property("activeFocusItem")).value<QQuickItem *>(); 
    if (item == NULL) qDebug() << "No item"; 

    // Create a key and a key event 
    Qt::Key key = Qt::Key_Left; 
    QKeyEvent* event = new QKeyEvent(QKeyEvent::KeyPress, 
            key, 
            Qt::NoModifier, 
            KeySequence(key).toString()); 

    // Send it to the focused QML item 
    QCoreApplication::postEvent(item,event); 
} 

如果給定的項目支持的按鍵事件,它將相應地作出反應。否則,收到的按鍵事件不會觸發任何響應。我已經用TextField,一個基於自定義Text的組件(只更新了text屬性和通過關鍵事件發送的文本)等來測試它,並且我還沒有遇到任何問題。直到我開始用ListView工作...

我試圖使用鍵盤的左右箭頭鍵使用我的我的映射器的mapToKey()功能(點這裏的關鍵事件被人爲地創建導航ListView映射硬件事件,如按真實按鈕到Qt事件)。在Qt 5.6中,將focus屬性設置爲true可以使用鍵進行導航(在5.8中,也可能是5.7,keyNavigationEnabled屬性必須設置爲true;在Qt 5.6中沒有這種屬性)。

ListView如下所示:

ListView { 
    id: list 
    orientation: Qt.Horizontal 
    width: rootWindow.width 
    height: 50 

    Keys.onPressed: { 
     console.log("list: " + event.key + " : " + event.text) 
     if (event.key == Qt.Key_Left) console.log("Moving to the left"); 
     else if (event.key == Qt.Key_Right) console.log("Moving to the right"); 
    } 

    model: ListModel { 
     id: items 
    } 
    delegate: Rectangle { 
     width: 50 
     height: 50 
     Text { 
      anchors.centerIn: parent 
      text: "[" + name + "]" 
     } 
    } 

    Component.onCompleted: function() { 
     for(var i = 1; i <= 100; i++) { 
      items.append({"name" : i}); 
     } 
    } 
    onFocusChanged: { 
     console.log("List focus has changed"); 
    } 
} 

我發現這個問題是奇怪的方式的關鍵事件是由該QML組件處理。它似乎試圖模仿基於動力學的滑動(考慮加速度),您可以在滾動瀏覽其中的項時使用鼠標執行滑動。這意味着:

  • 滾動視圖,如果方向鍵被保持的很長一段時間被觸發(約2秒) - 一旦啓用它不滾動單個項目,但多
  • 上述滾動觸發後,用戶可以繼續按方向鍵繼續快速滾動。此時,每個按鍵事件滾動單個項目也是可能的,但是...
  • 更改方向會導致上述行爲的重置,因此用戶需要執行另一個「觸發器滾動」事件才能滾動到相反的方向
  • 觸發多個單獨的按鍵事件也會觸發滾動,但此時一次只觸發一個項目。我上面提到的時間間隔似乎也不適用於此。用戶需要按給定的方向鍵7次(至少這是多少我已經計算在內)之前,他可以在列表中

似乎選擇下一個/上一個項目在內部映射需要一定的金額新聞發佈長按-X秒鍵事件實際觸發ListView某些響應。

現在我的一位同事創建了我們正在使用的ListView的自定義關鍵導航,它工作正常。不過,我想知道是否沒有一些祕密設置(或者我們都沒有錯過文檔中的備忘錄)來處理這個問題。我可以看到這種類型的與鍵的交互(即模擬加速)的應用,但對於我正在處理的場景,我真的不需要它,或者至少現在不需要。另外,如果我想在某個時刻添加僞加速部分,則知道事情是如何完成是非常有用的。

回答

2

當您按左/右箭頭鍵時,動力學滑動ListView是動畫ListView.highlight。爲了使其可見,我們可以添加一些代碼到您的列表:

ListView { 
    id: list 

    Keys.onPressed: { 
     console.log(list.currentIndex); 
     //... 
    } 
    delegate: Item { // so we can see highlight in background 
     width: 50 
     height: 50 
     Text { 
      anchors.centerIn: parent 
      text: "[" + name + "]" 
     } 
    } 
    highlight: Rectangle { 
     width: 50 
     height: 50 
     color: "pink" 
    } 
    //... 
} 

當你按下右箭頭鍵,currentIndex改變和高亮移動到該索引。你可以看到相同的動畫,如果你明確地改變currentIndex這樣的:

Button { 
    text: "go to 45" 
    onClicked: list.currentIndex = 45; 
} 

要自定義動畫,你可以改變ListView.highlightMoveDurationListView.highlightMoveVelocity屬性,或者設置ListView.highlightFollowsCurrentItem爲false將其關閉。您也可以按照ListView example code製作自己的高光動畫。

看起來內部映射需要一定量的按下 - 釋放或按住X秒鍵事件才能實際觸發ListView中的某些響應。

有在ListView沒有魔法處理按鍵事件的時候,它只是改變了currentIndex不斷和QML動畫可以完美地處理它。

+0

謝謝。你是對的。在Key.onPressed中添加一個'console.log'的確在'currentIndex'中顯示了一個變化。我只是沒有看到這種變化,因爲我沒有突出顯示,只有當currentIndex到達視圖的末尾時,列表滾動才變得可見。 :d – rbaleksandar