在ListView之间传递焦点

Phr*_*ogz 5 qt focus qml qtquickcontrols

我正在创建一个ListView支持多重选择的QML ,并将在我的应用程序中实例化多个。我需要将键盘焦点赋予特定的列表,处理该列表的按键,并根据焦点为选定的行绘制高亮显示。

但是,提供focus=true给ListView委托或ListView本身不会导致activeFocus出现在ListView上,也不会导致触发按键信号。

我创建了一个简单的示例应用程序来显示我的问题:

在此处输入图片说明

import QtQuick 2.7
import QtQuick.Window 2.0

Window {
  id:window; visible:true; width:400; height:160; color:'darkgray'

  Component {
    id: row
    Rectangle {
      id: root
      property int  i: index
      property bool current: ListView.isCurrentItem
      property bool focused: ListView.view.activeFocus
      width:parent.width; height:20
      color: current ? ( focused ? 'pink' : 'lightblue' ) : 'lightgray'
      MouseArea {
        anchors.fill: parent
        onClicked: {
          root.ListView.view.currentIndex = i;
          root.ListView.view.focus = true;
        }
      }
      Text { anchors.fill:parent; text:modelData }
    }
  }

  Component {
    id: myList
    ListView {
      delegate: row
      width:window.width/2-10; height:window.height; y:5
      Keys.onUpPressed:   decrementCurrentIndex()
      Keys.onDownPressed: incrementCurrentIndex()
    }
  }

  Loader {
    sourceComponent:myList; x:5
    onLoaded: item.model = ['a','b','c','d']
  }
  Loader {
    sourceComponent:myList; x:window.width/2
    onLoaded: item.model = ['1','2','3','4','5']
  }
}
Run Code Online (Sandbox Code Playgroud)

单击任一列表都不会将所选行变成粉红色,并且按向上/向下键不会调整选择。

如何将焦点传递给特定对象ListView,使得(a)一次仅一个ListView拥有焦点,并且(b)我可以检测到ListView何时拥有该焦点,并且(c)它允许键盘信号仅适用于该ListView同时集中精力?

我正在使用Qt 5.7,以防万一。


我尝试过的事情失败了:

  • focus=true在Rectangle而不是ListView上进行设置。
  • 设置focused要监视的属性,ListView.view.focus而不是activeFocus:这允许两个列表同时变为粉红色。
  • 通过Qt Quick中的Keyboard Focus读取并将Rectangle或ListView包裹在FocusScope。(这是一件痛苦的事,所有的接口都要一起转发。)

    • 视情况重新阅读该页面,并将两者包装Loader在一个单独的容器中FocusScope。显然,允许同时作为两个ListView进行诅咒具有焦点,这违反了我对文档这一部分的阅读:

      在每个焦点范围内,一个对象可能已Item::focus设置为true。如果设置了多个Item focus属性,则最后一个设置焦点的类型将设置focus,而其他项则未设置,这与没有焦点范围的情况类似。

  • 将ListView包裹在项目中,然后将Keys处理程序放在该项目上,然后尝试使该项目集中。

  • interactive:false在ListView上设置。
  • keyNavigationEnabled:false在ListView上设置。("ListView.keyNavigationEnabled" is not available in QtQuick 2.7尽管Help声明它是在5.7中引入的,但这奇怪地产生了收益,并暗示QtQuick 2.7是正确的import语句。)
  • 戴上focus:true我能找到的几乎所有物体,以防万一。

注意:我意识到标准ListView使用a highlight来显示选择,并使用键盘导航来调整currentItem。但是,由于我的需求需要同时选择多个项目,因此必须特别管理突出显示和键盘。


编辑:这是一个更简单的测试用例,其行为不像我期望的那样:

import QtQuick 2.7
import QtQuick.Window 2.0

Window {
  id:window; visible:true; width:400; height:160; color:'darkgray'

  FocusScope {
    Rectangle {
      width: window.width/2-6; height:window.height-8; x:4; y:4
      color: focus ? 'red' : 'gray'
      MouseArea { anchors.fill:parent; onClicked:parent.focus=true }
      Text { text:'focused'; visible:parent.activeFocus }
      Keys.onSpacePressed: console.log('space left')
    }
    Rectangle {
      width: window.width/2-6; height:window.height-8; x:window.width/2+2; y:4
      color: focus ? 'red' : 'gray'
      MouseArea { anchors.fill:parent; onClicked:parent.focus=true }
      Text { text:'focused'; visible:parent.activeFocus }
      Keys.onSpacePressed: console.log('space right')
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

单击每个矩形使其变为红色,并且在任何给定时间只允许一个为红色。(这很好。)但是,由于“矩形”没有显示,因此不会显示“聚焦”文本activeFocus。此外,space当任何一个都聚焦时,按永不记录消息。

编辑2:哇。如果我删除FocusScope,它会按预期工作:焦点仍然是排他的,activeFocus被授予并且space工作正常。也许我上面的问题是,因为ListViewFocusScope(根据文档)。

编辑3:Per Mitch在下面的注释中,focus:true在上设置FocusScope也可以使所有内容与FocusScope一起正常工作。但是,按照我在下面的回答(以及Mitch的评论),FocusScope并不是使我的两个简化示例应用程序都能正常工作所必需的。

Mit*_*tch 5

如果您在原始示例中打印了活动焦点项目

onActiveFocusItemChanged: print(activeFocusItem)
Run Code Online (Sandbox Code Playgroud)

您会看到没有一个装载机能够集中注意力;它始终是窗口的根项。

如果您设置focus: true了其中一个装载机,那么它将具有重点:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    id: window
    visible: true
    width: 400
    height: 160
    color: 'darkgray'

    onActiveFocusItemChanged: print(activeFocusItem)

    Component {
        id: row
        Rectangle {
            id: root
            property int i: index
            property bool current: ListView.isCurrentItem
            property bool focused: ListView.view.activeFocus
            width: parent.width
            height: 20
            color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    root.ListView.view.currentIndex = i
                    root.ListView.view.focus = true
                }
            }
            Text {
                anchors.fill: parent
                text: modelData
            }
        }
    }

    Component {
        id: myList
        ListView {
            delegate: row
            width: window.width / 2 - 10
            height: window.height
            y: 5
            Keys.onUpPressed: decrementCurrentIndex()
            Keys.onDownPressed: incrementCurrentIndex()
        }
    }

    Loader {
        objectName: "loader1"
        sourceComponent: myList
        focus: true
        x: 5
        onLoaded: item.model = ['a', 'b', 'c', 'd']
    }
    Loader {
        objectName: "loader2"
        sourceComponent: myList
        x: window.width / 2
        onLoaded: item.model = ['1', '2', '3', '4', '5']
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,现在,当您单击第二个视图的委托时,第二个视图将不再具有焦点。如果我们宣布它们都具有焦点,那么我们将失去对最终目标的控制。实际上,即使我们确实声明它们都具有焦点,单击第二个视图的委托也不会赋予该视图主动焦点,因为当第一个加载器获得焦点时,它已经失去了焦点。换句话说,要使其正常工作,您还必须给予加载程序以焦点,这违背了将漂亮的少量捆绑代表组件的全部目的:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    id: window
    visible: true
    width: 400
    height: 160
    color: 'darkgray'

    onActiveFocusItemChanged: print(activeFocusItem)

    Component {
        id: row
        Rectangle {
            id: root
            property int i: index
            property bool current: ListView.isCurrentItem
            property bool focused: ListView.view.activeFocus
            width: parent.width
            height: 20
            color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    root.ListView.view.currentIndex = i
                    root.ListView.view.parent.focus = true
                    root.ListView.view.focus = true
                }
            }
            Text {
                anchors.fill: parent
                text: modelData
            }
        }
    }

    Component {
        id: myList
        ListView {
            delegate: row
            width: window.width / 2 - 10
            height: window.height
            y: 5
            Keys.onUpPressed: decrementCurrentIndex()
            Keys.onDownPressed: incrementCurrentIndex()
        }
    }

    Loader {
        objectName: "loader1"
        sourceComponent: myList
        x: 5
        onLoaded: item.model = ['a', 'b', 'c', 'd']
    }
    Loader {
        objectName: "loader2"
        sourceComponent: myList
        x: window.width / 2
        onLoaded: item.model = ['1', '2', '3', '4', '5']
    }
}
Run Code Online (Sandbox Code Playgroud)

在这一点上,我只是放弃并强迫积极关注:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    id: window
    visible: true
    width: 400
    height: 160
    color: 'darkgray'

    onActiveFocusItemChanged: print(activeFocusItem)

    Component {
        id: row
        Rectangle {
            id: root
            objectName: ListView.view.objectName + "Rectangle" + index
            property int i: index
            property bool current: ListView.isCurrentItem
            property bool focused: ListView.view.activeFocus
            width: parent.width
            height: 20
            color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    root.ListView.view.currentIndex = i
                    root.ListView.view.forceActiveFocus()
                }
            }
            Text {
                anchors.fill: parent
                text: modelData
            }
        }
    }

    Component {
        id: myList
        ListView {
            objectName: parent.objectName + "ListView"
            delegate: row
            width: window.width / 2 - 10
            height: window.height
            y: 5
            Keys.onUpPressed: decrementCurrentIndex()
            Keys.onDownPressed: incrementCurrentIndex()
        }
    }

    Loader {
        id: loader1
        objectName: "loader1"
        sourceComponent: myList
        x: 5
        onLoaded: item.model = ['a', 'b', 'c', 'd']
    }
    Loader {
        objectName: "loader2"
        sourceComponent: myList
        x: window.width / 2
        onLoaded: item.model = ['1', '2', '3', '4', '5']
    }
}
Run Code Online (Sandbox Code Playgroud)

我真的不喜欢聚焦系统。我并不是说我可以提出更好的建议,但这并不容易使用。

  • 顺便说一句,顺便说一句,谢谢[forceActiveFocus()`](http://doc.qt.io/qt-5/qml-qtquick-item.html#forceActiveFocus-method)。这就像一种魅力。 (3认同)